A linha de móveis que combina
Uma loja vende duas linhas completas: moderna e vitoriana. Você não escolhe cadeira, mesa e sofá peça por peça — escolhe a LINHA, e a fábrica daquela linha entrega o conjunto. É impossível sair da loja com uma cadeira vitoriana de pés torneados ao lado de uma mesa moderna de vidro: quem garante a combinação não é o seu bom gosto, é a fábrica, que só produz peças da própria linha.
O problema
Alguns objetos só fazem sentido juntos: um botão do tema escuro ao lado de um checkbox do tema claro denuncia o bug na primeira tela. Criando cada produto isoladamente com new, nada impede a mistura de variantes incompatíveis.
E espalhar condicionais de variante por cada ponto de criação multiplica os lugares que precisam mudar quando surge uma variante nova — basta esquecer um para a inconsistência aparecer.
A relação com o Factory Method é direta: o Factory Method cria UM produto por vez; o Abstract Factory agrupa vários métodos de criação sob um mesmo contrato, amarrando-os pela variante. Na prática, cada método da fábrica abstrata é um factory method — o padrão é a composição deles.
Essa amarração define os eixos de extensão do padrão: adicionar uma FAMÍLIA nova (linha industrial, tema de alto contraste) é barato — uma classe nova, nenhum código existente muda. Adicionar um PRODUTO novo à família (criarLuminaria) é caro — muda a interface da fábrica e todas as concretas. Escolha o padrão quando as famílias variam mais que a composição da família.
A garantia de consistência é estrutural, não convencional: como o cliente só enxerga a interface da fábrica, o sistema de tipos impede que um produto vitoriano apareça no fluxo moderno. A decisão de qual fábrica usar sobe para a borda da aplicação — configuração, injeção de dependência ou leitura de ambiente no boot.
- Cliente
- pede a famíliaFabricaDeMoveis (interface)
- variante resolvida no bootFabricaModerna
- cria em conjuntoCadeira + Mesa + Sofá modernos
- 1
Declarar a família
A interface da fábrica lista um método de criação por produto (botão, checkbox…).
- 2
Uma fábrica por variante
Cada tema/plataforma implementa a fábrica criando só produtos da própria linha.
- 3
Escolher uma vez
Na composição da aplicação, resolve-se qual fábrica concreta usar.
- 4
Montar só com abstrações
O cliente chama criarBotao()/criarCheckbox() — nunca dá new em produto concreto.
Navegue pelas camadas
Camada 1/4Cliente
use ← →Camada 1
Cliente
usa abstrações, nunca dá new
Recebe a fábrica pela interface e monta o que precisa chamando os métodos de criação. Não conhece nenhuma classe concreta — nem de fábrica, nem de produto. É por isso que trocar a variante inteira não exige tocar no cliente.
No código
function montarFormulario(fabrica: UIFactory) {
const botao = fabrica.criarBotao();
}Se violar: um new BotaoEscuro() dentro do cliente reata o acoplamento à variante e abre a porta para misturar famílias.
Estrutura
Código
// Produtos: cada família implementa as mesmas interfaces
interface Botao { renderizar(): string; }
interface Checkbox { renderizar(): string; }
// Fábrica abstrata: um método de criação por produto da família
interface UIFactory {
criarBotao(): Botao;
criarCheckbox(): Checkbox;
}
// Família "tema escuro" — produtos que combinam entre si
class BotaoEscuro implements Botao {
renderizar() { return "<button class='dark'>OK</button>"; }
}
class CheckboxEscuro implements Checkbox {
renderizar() { return "<input type='checkbox' class='dark'>"; }
}
class TemaEscuroFactory implements UIFactory {
criarBotao() { return new BotaoEscuro(); }
criarCheckbox() { return new CheckboxEscuro(); }
}
// Cliente conhece só as abstrações — a família chega pronta
function montarFormulario(fabrica: UIFactory): string {
const botao = fabrica.criarBotao();
const check = fabrica.criarCheckbox();
return check.renderizar() + botao.renderizar();
}
// A variante é decidida UMA vez, na composição da aplicação
console.log(montarFormulario(new TemaEscuroFactory()));from abc import ABC, abstractmethod
class Botao(ABC):
@abstractmethod
def renderizar(self) -> str: ...
class Checkbox(ABC):
@abstractmethod
def renderizar(self) -> str: ...
# Fábrica abstrata: um método de criação por produto da família
class UIFactory(ABC):
@abstractmethod
def criar_botao(self) -> Botao: ...
@abstractmethod
def criar_checkbox(self) -> Checkbox: ...
class BotaoEscuro(Botao):
def renderizar(self) -> str:
return "<button class='dark'>OK</button>"
class CheckboxEscuro(Checkbox):
def renderizar(self) -> str:
return "<input type='checkbox' class='dark'>"
class TemaEscuroFactory(UIFactory):
def criar_botao(self) -> Botao:
return BotaoEscuro()
def criar_checkbox(self) -> Checkbox:
return CheckboxEscuro()
# Cliente conhece só as abstrações — a família chega pronta
def montar_formulario(fabrica: UIFactory) -> str:
botao = fabrica.criar_botao()
check = fabrica.criar_checkbox()
return check.renderizar() + botao.renderizar()
print(montar_formulario(TemaEscuroFactory()))Casos de uso
Tema claro/escuro em um design system
Cenário
Um SaaS B2B tem design system com botão, input, modal e tabela — cada componente com versão clara e escura que precisam aparecer sempre juntas.
Como o padrão entra
Uma UIFactory por tema cria a família completa de componentes. O app resolve a fábrica uma vez (preferência do usuário) e todo o resto do código monta telas sem saber qual tema está ativo — impossível renderizar modal claro sobre fundo escuro.
Trade-off: Cada componente novo do design system exige mexer na interface da fábrica e em todas as concretas — o custo de manter a família fechada.
Provedores de pagamento intercambiáveis
Cenário
Uma fintech integra dois PSPs; cada um exige um trio que precisa combinar: cliente de cobrança, parser de webhook e validador de assinatura — misturar peças de PSPs diferentes gera erro silencioso.
Como o padrão entra
Uma PspFactory por provedor cria o trio coerente. O orquestrador de cobranças recebe a fábrica do PSP escolhido por transação e nunca corre o risco de validar o webhook do provedor A com a chave do provedor B.
Trade-off: A interface comum vira o mínimo denominador entre provedores — recursos exclusivos de um PSP ficam de fora do contrato ou vazam por interfaces paralelas.
E-commerce multi-país
Cenário
Uma operação de e-commerce atua no Brasil e no México; imposto, formatação de moeda e regras de frete variam por país, e usar a regra de um com a moeda do outro corrompe o checkout.
Como o padrão entra
Uma RegiaoFactory por país cria calculadora de imposto, formatador de moeda e política de frete como família fechada. O checkout resolve a fábrica pelo país do pedido e opera consistente do carrinho à nota.
Trade-off: Países muito parecidos geram fábricas quase idênticas — quando a diferença cabe em parâmetros, configuração por dados vence classes por variante.
A fábrica que o cliente fura com new
Compila, roda, passa no code review. E quebra depois.
A Abstract Factory está montada, as famílias existem — mas em algum ponto o cliente ainda instancia um produto concreto na mão. A consistência que o padrão prometia vira convenção outra vez.
interface UIFactory {
criarBotao(): Botao;
criarCheckbox(): Checkbox;
}
class TemaEscuroFactory implements UIFactory {
criarBotao() { return new BotaoEscuro(); }
criarCheckbox() { return new CheckboxEscuro(); }
}
// A "familia" existe... e o cliente continua misturando na mao.
function montarFormulario() {
const fabrica = new TemaEscuroFactory();
const botao = fabrica.criarBotao();
const check = new CheckboxClaro(); // <- furou a fabrica
return check.renderizar() + botao.renderizar();
}
// Tema novo nao e o problema: o problema e que new concreto
// ainda vive no cliente. A garantia de consistencia morreu.O que quebra
- Na telaBotão escuro ao lado de checkbox claro: a mistura incompatível volta a ser possível.
- Ao trocar o temaParte da UI muda com a fábrica; a peça criada com new fica presa na variante antiga.
- Na revisãoCada
new ProdutoXno cliente é um furo na fronteira — e eles se espalham silenciosos.
A saída: Produto só nasce pela fábrica. Se faltar um método de criação, ele entra na interface — não se contorna com new no cliente. Construtores inacessíveis fora do módulo reforçam a regra.
Armadilhas
Família de um produto só
Se a sua fábrica abstrata tem um único método de criação, você tem um Factory Method com nome pomposo e uma camada a mais. O Abstract Factory só paga o próprio custo quando existe uma FAMÍLIA — dois ou mais produtos que precisam variar juntos.
Novo produto na família dói
Adicionar criarLuminaria() muda a interface da fábrica e quebra todas as concretas de uma vez. Se a composição da família muda com frequência, o padrão trabalha contra você — reavalie o recorte ou aceite interfaces segregadas por grupo de produtos.
Cliente que fura a fábrica
Um único new CadeiraVitoriana() direto no cliente quebra a garantia de consistência sem nenhum aviso — o código compila e o bug aparece na tela. A regra 'produto só nasce na fábrica' precisa de reforço real: revisão, regra de lint ou construtores inacessíveis fora do módulo.
Quando usar × quando evitar
Use quando
4- O sistema cria famílias de objetos relacionados que precisam ser usados juntos (tema, plataforma, região, provedor).
- Variantes inteiras trocam em conjunto e você quer decidir a variante em um único ponto.
- Você quer que o sistema de tipos impeça a mistura de produtos incompatíveis, em vez de confiar em disciplina.
- Já existem vários Factory Methods correlacionados pela mesma variante.
Evite quando
3- Só existe um produto por variante — um Factory Method simples resolve com menos cerimônia.
- A composição da família muda com frequência: cada produto novo altera a interface e todas as fábricas concretas.
- Só há uma família e nenhuma previsão concreta de outra — abstração especulativa.
Testar o que ficou
3 armadilhas de Abstract Factory viram perguntas, com o nome do padrão escondido, misturadas com padrões parecidos.
Onde isto aparece de verdade
Você já usa isto, talvez sem saber o nome.
Componentes do React NativeO mesmo<Text>vira UILabel no iOS e TextView no Android — uma família inteira trocada de uma vez.Drivers de bancoO driver entrega conexão, cursor e transação combinando entre si; trocar de banco troca a família toda.
O padrão em uma linha
Sem nome de domínio, sem cerimônia. Só a ideia.
// Família de produtos relacionados, sem new concreto.
const ui = temaEscuro ? new DarkFactory() : new LightFactory();
const botao = ui.criarBotao();O que ele cobra
2 saltos a mais entre a chamada e o efeito.
- Uma interface de fábrica por família, mais as implementações concretas de cada uma
- Adicionar um produto novo à família obriga a mexer em todas as fábricas existentes
Não vale se: os produtos não formam famílias que precisam ser trocadas juntas — sem essa restrição, é estrutura sem propósito.