CriacionalIntermediário7 min de leitura8 seções1994, Marco de referência: a ideia é mais velha que a data

Abstract Factory

Cria famílias inteiras de objetos relacionados através de uma interface única, garantindo que os produtos de uma mesma variante sempre combinem entre si.

Em 10 segundos

Uma fábrica abstrata entrega famílias inteiras de objetos compatíveis entre si: o cliente escolhe a fábrica uma única vez e nunca mais decide qual variante instanciar — a consistência vem de graça.

  • #gof
  • #familias-de-objetos
  • #consistencia
  • #variantes
Analogia

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.

01Conceito

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.

Como se encaixa
  1. Cliente
  2. pede a famíliaFabricaDeMoveis (interface)
  3. variante resolvida no bootFabricaModerna
  4. cria em conjuntoCadeira + Mesa + Sofá modernos
O cliente fala só com a interface; a fábrica concreta escolhida garante que todos os produtos criados pertencem à mesma variante.
Passo a passoO fluxo, passo a passo
  1. 1

    Declarar a família

    A interface da fábrica lista um método de criação por produto (botão, checkbox…).

  2. 2

    Uma fábrica por variante

    Cada tema/plataforma implementa a fábrica criando só produtos da própria linha.

  3. 3

    Escolher uma vez

    Na composição da aplicação, resolve-se qual fábrica concreta usar.

  4. 4

    Montar só com abstrações

    O cliente chama criarBotao()/criarCheckbox() — nunca dá new em produto concreto.

02Anatomia

Navegue pelas camadas

Camada 1/4Cliente

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.

03Estrutura

Estrutura

Diagrama de classes
04Implementação

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()));
05No mundo real

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 ProdutoX no 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.

07Cuidado

Armadilhas

  1. 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.

  2. 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.

  3. 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.

08Decisão

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.

Costuma ser confundido com

Onde isto aparece

Continue por aqui