Salve salve Pythonista
Os padrões de projeto são soluções comprovadas para problemas comuns no desenvolvimento de software.
Em Python, aplicar padrões de projeto pode aumentar a manutenibilidade, flexibilidade e reusabilidade do código.
Neste artigo, abordaremos o padrão de projeto Abstract Factory.
Vamos explorar seu intuito, o problema que resolve, a estrutura, aplicabilidade e como implementá-lo na prática com Python.
Com exemplos práticos, você entenderá como aplicar o Abstract Factory para melhorar suas aplicações Python.
Vá Direto ao Assunto…
- O Intuito de Utilizar o Abstract Factory em Python
- O Problema que o Abstract Factory Resolve
- O Racional por Trás do Abstract Factory como Solução
- Estrutura do Abstract Factory
- Aplicabilidade do Abstract Factory
- Implementando o Abstract Factory na Prática com Python
- Exemplos Práticos de Abstract Factory em Python
O Intuito de Utilizar o Abstract Factory em Python
O Abstract Factory é um padrão de criação que fornece uma interface para criar famílias de objetos relacionados sem especificar suas classes concretas.
Em Python, utilizar o Abstract Factory ajuda a isolar a criação de objetos, promovendo um código mais flexível e extensível.
Isso é especialmente útil em sistemas que precisam trabalhar com múltiplas variantes de produtos que pertencem a uma mesma família.
O Problema que o Abstract Factory Resolve
Em aplicações complexas, a criação de objetos pode se tornar complicada e acoplada.
Sem um padrão de criação adequado, gerenciar diferentes variantes de produtos pode levar a um código difícil de manter e escalar.
Além disso, a troca de implementações concretas pode se tornar um pesadelo, já que o código depende fortemente das classes específicas utilizadas.
O Racional por Trás do Abstract Factory como Solução
O Abstract Factory resolve esses problemas ao encapsular a criação de objetos relacionados.
Ele permite que o sistema seja independente das classes concretas necessárias para a criação dos objetos.
Isso promove a flexibilidade, permitindo que novas famílias de produtos sejam adicionadas sem modificar o código existente.
Estrutura do Abstract Factory
A estrutura do Abstract Factory envolve os seguintes componentes:
- AbstractFactory: Interface que declara métodos para criar cada tipo de produto.
- ConcreteFactory: Implementações concretas da AbstractFactory, responsáveis por criar objetos de uma família específica.
- AbstractProduct: Interfaces para diferentes tipos de produtos.
- ConcreteProduct: Implementações concretas dos AbstractProducts.
Diagrama de Classe
1
2
3
4
5
6
7
8
9
AbstractFactory
|-- ConcreteFactory1
|-- ConcreteFactory2
AbstractProductA
|-- ConcreteProductA1
|-- ConcreteProductA2
AbstractProductB
|-- ConcreteProductB1
|-- ConcreteProductB2
Aplicabilidade do Abstract Factory
O Abstract Factory é aplicável quando:
- Famílias de objetos são projetadas para serem usadas juntas.
- O sistema deve ser independente de como seus produtos são criados, compostos e representados.
- É necessário que o sistema seja configurado com uma das várias famílias de produtos.
- Mudanças nas classes concretas não devem afetar o sistema.
Antes de continuar… Está curtindo esse conteúdo?
Que tal avançar ainda mais no seu aprendizado?
Implementando o Abstract Factory na Prática com Python
Vamos implementar o padrão Abstract Factory em Python com um exemplo prático.
Imagine que estamos desenvolvendo um sistema de GUI que deve funcionar com diferentes estilos de botões e caixas de texto.
Passo 1: Definir Interfaces dos Produtos
Primeiro, definimos as interfaces para os produtos que serão criados pelas fábricas.
1
2
3
4
5
6
7
8
9
10
11
12
from abc import ABC, abstractmethod
# Interfaces dos Produtos
class Botao(ABC):
@abstractmethod
def desenhar(self):
pass
class CaixaDeTexto(ABC):
@abstractmethod
def desenhar(self):
pass
Explicação do código:
-
Importações: Importamos
ABC
eabstractmethod
para criar classes abstratas. -
Interfaces dos Produtos: Definimos as classes abstratas
Botao
eCaixaDeTexto
com o método abstratodesenhar
.
Passo 2: Implementar Produtos Concretos
Agora, implementamos as classes concretas que herdam das interfaces dos produtos.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Produtos Concretos para Tema Claro
class BotaoClaro(Botao):
def desenhar(self):
print("Desenhando Botão Claro")
class CaixaDeTextoClaro(CaixaDeTexto):
def desenhar(self):
print("Desenhando Caixa de Texto Clara")
# Produtos Concretos para Tema Escuro
class BotaoEscuro(Botao):
def desenhar(self):
print("Desenhando Botão Escuro")
class CaixaDeTextoEscuro(CaixaDeTexto):
def desenhar(self):
print("Desenhando Caixa de Texto Escura")
Explicação do código:
-
Produtos Concretos: Criamos
BotaoClaro
,CaixaDeTextoClaro
,BotaoEscuro
eCaixaDeTextoEscuro
que implementam os métodosdesenhar
de suas respectivas interfaces.
Passo 3: Definir a Interface da Fábrica Abstrata
Definimos a interface que declara métodos para criar cada tipo de produto.
1
2
3
4
5
6
7
8
9
# Interface da Fábrica Abstrata
class FabricaGUI(ABC):
@abstractmethod
def criar_botao(self) -> Botao:
pass
@abstractmethod
def criar_caixa_de_texto(self) -> CaixaDeTexto:
pass
Explicação do código:
-
Fábrica Abstrata: A classe
FabricaGUI
declara os métodoscriar_botao
ecriar_caixa_de_texto
que devem ser implementados pelas fábricas concretas.
Passo 4: Implementar Fábricas Concretas
Implementamos as fábricas concretas que criam os produtos específicos.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Fábricas Concretas
class FabricaClaro(FabricaGUI):
def criar_botao(self) -> Botao:
return BotaoClaro()
def criar_caixa_de_texto(self) -> CaixaDeTexto:
return CaixaDeTextoClaro()
class FabricaEscuro(FabricaGUI):
def criar_botao(self) -> Botao:
return BotaoEscuro()
def criar_caixa_de_texto(self) -> CaixaDeTexto:
return CaixaDeTextoEscuro()
Explicação do código:
-
FabricaClaro: Implementa
criar_botao
ecriar_caixa_de_texto
retornando objetos claros. - FabricaEscuro: Implementa os mesmos métodos retornando objetos escuros.
Passo 5: Utilizar a Fábrica Abstrata
Finalmente, utilizamos a fábrica abstrata para criar os produtos sem depender das classes concretas.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def aplicar_tema(fabrica: FabricaGUI):
botao = fabrica.criar_botao()
caixa_texto = fabrica.criar_caixa_de_texto()
botao.desenhar()
caixa_texto.desenhar()
# Exemplo com Tema Claro
print("Aplicando Tema Claro:")
fabrica_claro = FabricaClaro()
aplicar_tema(fabrica_claro)
# Exemplo com Tema Escuro
print("\nAplicando Tema Escuro:")
fabrica_escuro = FabricaEscuro()
aplicar_tema(fabrica_escuro)
Explicação do código:
-
Função
aplicar_tema
: Recebe uma fábrica abstrata, cria os produtos e chama seus métodosdesenhar
. -
Aplicação do Tema Claro e Escuro: Criamos instâncias de
FabricaClaro
eFabricaEscuro
e aplicamos os temas, observando como os objetos são criados de forma abstrata.
Saída Esperada:
E a saída será:
1
2
3
4
5
6
7
Aplicando Tema Claro:
Desenhando Botão Claro
Desenhando Caixa de Texto Clara
Aplicando Tema Escuro:
Desenhando Botão Escuro
Desenhando Caixa de Texto Escura
Exemplos Práticos de Abstract Factory em Python
Vamos explorar mais dois exemplos práticos onde o Abstract Factory pode ser aplicado em Python.
Exemplo 1: Fabricação de Carros
Imagine que estamos desenvolvendo um sistema que deve funcionar com diferentes tipos de carros (SUV, Sedã). Cada tipo de carro possui partes diferentes como Motor e Roda.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from abc import ABC, abstractmethod
# Interfaces dos Produtos
class Motor(ABC):
@abstractmethod
def especificacoes(self):
pass
class Roda(ABC):
@abstractmethod
def tipo(self):
pass
# Produtos Concretos
class MotorV8(Motor):
def especificacoes(self):
print("Motor V8: Potência de 450cv")
class RodaEsportiva(Roda):
def tipo(self):
print("Roda Esportiva: 18 polegadas")
class MotorEconomico(Motor):
def especificacoes(self):
print("Motor Econômico: Consumo reduzido")
class RodaCompacta(Roda):
def tipo(self):
print("Roda Compacta: 16 polegadas")
# Fábrica Abstrata
class FabricaCarro(ABC):
@abstractmethod
def criar_motor(self) -> Motor:
pass
@abstractmethod
def criar_roda(self) -> Roda:
pass
# Fábricas Concretas
class FabricaEsportiva(FabricaCarro):
def criar_motor(self) -> Motor:
return MotorV8()
def criar_roda(self) -> Roda:
return RodaEsportiva()
class FabricaEconomica(FabricaCarro):
def criar_motor(self) -> Motor:
return MotorEconomico()
def criar_roda(self) -> Roda:
return RodaCompacta()
# Utilização
def montar_carro(fabrica: FabricaCarro):
motor = fabrica.criar_motor()
roda = fabrica.criar_roda()
motor.especificacoes()
roda.tipo()
print("Montando Carro Esportivo:")
fabrica_esportiva = FabricaEsportiva()
montar_carro(fabrica_esportiva)
print("\nMontando Carro Econômico:")
fabrica_economica = FabricaEconomica()
montar_carro(fabrica_economica)
Saída Esperada:
E a saída será:
1
2
3
4
5
6
7
Montando Carro Esportivo:
Motor V8: Potência de 450cv
Roda Esportiva: 18 polegadas
Montando Carro Econômico:
Motor Econômico: Consumo reduzido
Roda Compacta: 16 polegadas
Exemplo 2: Criação de Interfaces de Usuário
Suponha que estamos desenvolvendo uma aplicação que deve suportar diferentes sistemas operacionais (Windows, MacOS). Cada sistema operacional possui estilos diferentes para botões e menus.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from abc import ABC, abstractmethod
# Interfaces dos Produtos
class Botao(ABC):
@abstractmethod
def renderizar(self):
pass
class Menu(ABC):
@abstractmethod
def exibir(self):
pass
# Produtos Concretos
class BotaoWindows(Botao):
def renderizar(self):
print("Renderizando Botão no estilo Windows")
class MenuWindows(Menu):
def exibir(self):
print("Exibindo Menu no estilo Windows")
class BotaoMac(Botao):
def renderizar(self):
print("Renderizando Botão no estilo MacOS")
class MenuMac(Menu):
def exibir(self):
print("Exibindo Menu no estilo MacOS")
# Fábrica Abstrata
class FabricaInterface(ABC):
@abstractmethod
def criar_botao(self) -> Botao:
pass
@abstractmethod
def criar_menu(self) -> Menu:
pass
# Fábricas Concretas
class FabricaWindows(FabricaInterface):
def criar_botao(self) -> Botao:
return BotaoWindows()
def criar_menu(self) -> Menu:
return MenuWindows()
class FabricaMac(FabricaInterface):
def criar_botao(self) -> Botao:
return BotaoMac()
def criar_menu(self) -> Menu:
return MenuMac()
# Utilização
def configurar_interface(fabrica: FabricaInterface):
botao = fabrica.criar_botao()
menu = fabrica.criar_menu()
botao.renderizar()
menu.exibir()
print("Configurando Interface para Windows:")
fabrica_windows = FabricaWindows()
configurar_interface(fabrica_windows)
print("\nConfigurando Interface para MacOS:")
fabrica_mac = FabricaMac()
configurar_interface(fabrica_mac)
Saída Esperada:
E a saída será:
1
2
3
4
5
6
7
Configurando Interface para Windows:
Renderizando Botão no estilo Windows
Exibindo Menu no estilo Windows
Configurando Interface para MacOS:
Renderizando Botão no estilo MacOS
Exibindo Menu no estilo MacOS
Curtiu esse conteúdo?
Que tal receber 30 dias de conteúdo direto na sua Caixa de Entrada?

Conclusão
O padrão de projeto Abstract Factory é uma ferramenta poderosa para criar famílias de objetos relacionados de forma abstrata e flexível.
Em Python, sua implementação promove um código mais organizado, extensível e manutenível, facilitando a gestão de diferentes variantes de produtos sem acoplamento direto às suas implementações concretas.
Através dos exemplos apresentados, vimos como aplicar o Abstract Factory em diferentes cenários práticos, desde interfaces gráficas até sistemas automotivos.
Incorporar padrões de projeto como o Abstract Factory em suas aplicações Python pode significativamente melhorar a estrutura e a qualidade do seu código, tornando-o mais robusto e adaptável às mudanças futuras.