GoF, p. 87 também chamado de Kit
Fábrica Abstrata
Abstract Factory
Uma fábrica de fábricas: cria famílias inteiras de objetos combináveis.
Fornecer uma interface para criar famílias de objetos relacionados ou dependentes sem especificar suas classes concretas.
A loja de móveis por estilo
Você entra numa loja e escolhe o estilo: Vitoriano ou Moderno. A partir daí, o sofá, a poltrona e a mesinha de centro que você recebe combinam entre si — você nunca pediu “o sofá vitoriano”, pediu “um sofá” para a loja vitoriana. Trocar de estilo é trocar de loja, e todo o conjunto muda junto, sem risco de misturar um sofá moderno com uma poltrona vitoriana.
Seu sistema precisa produzir vários objetos que só fazem sentido juntos (uma “família”). Se cada ponto do código instanciar a classe concreta diretamente com `new`, duas coisas ruins acontecem: (1) espalha-se a decisão de “qual família usar” por dezenas de arquivos, e (2) nada impede que alguém misture peças de famílias diferentes e quebre a coerência.
Declare uma interface para cada produto da família (Cadeira, Sofá, Mesa) e uma interface de fábrica com um método de criação por produto. Cada família concreta ganha sua própria fábrica, que só sabe produzir peças compatíveis entre si. O cliente recebe a fábrica pronta e conversa apenas com as interfaces — ele nunca vê uma classe concreta.
- Vários
if (tema === "escuro")espalhados decidindo qual classe instanciar. - Bugs do tipo “botão do tema claro apareceu na tela escura”.
Estrutura
- AbstractFactory
- Declara os métodos de criação, um por tipo de produto.
- ConcreteFactory
- Implementa a criação de uma família específica e coerente.
- AbstractProduct
- Interface comum a todas as variantes de um mesmo produto.
- ConcreteProduct
- Produto de uma família, criado pela fábrica correspondente.
- Client
- Usa apenas AbstractFactory e AbstractProduct.
Implementação
// ── Produtos abstratos ────────────────────────────────
class Botao { render() { throw new Error('abstrato'); } }
class Checkbox{ render() { throw new Error('abstrato'); } }
// ── Família 1: macOS ──────────────────────────────────
class BotaoMac extends Botao { render() { return '🍎 [ botão arredondado ]'; } }
class CheckboxMac extends Checkbox { render() { return '🍎 ( ✓ )'; } }
// ── Família 2: Windows ────────────────────────────────
class BotaoWin extends Botao { render() { return '🪟 [ botão retangular ]'; } }
class CheckboxWin extends Checkbox { render() { return '🪟 [x]'; } }
// ── A fábrica abstrata: um método por produto ─────────
class FabricaUI {
criarBotao() { throw new Error('abstrato'); }
criarCheckbox() { throw new Error('abstrato'); }
}
// Cada fábrica concreta produz SÓ peças coerentes entre si.
class FabricaMac extends FabricaUI {
criarBotao() { return new BotaoMac(); }
criarCheckbox() { return new CheckboxMac(); }
}
class FabricaWin extends FabricaUI {
criarBotao() { return new BotaoWin(); }
criarCheckbox() { return new CheckboxWin(); }
}
// ── Cliente: não conhece NENHUMA classe concreta ──────
function renderizarFormulario(fabrica) {
const botao = fabrica.criarBotao();
const check = fabrica.criarCheckbox();
return [check.render(), botao.render()].join('\n');
}
// A escolha da família acontece em UM único lugar.
const fabrica = navigator.platform.startsWith('Mac')
? new FabricaMac()
: new FabricaWin();
console.log(renderizarFormulario(fabrica)); - javax.xml.parsers.DocumentBuilderFactory (Java)
- java.awt.Toolkit — cria peças de UI da plataforma
- Drivers de banco: cada driver produz Connection, Statement e ResultSet coerentes
Consequências
- Garante que os produtos usados juntos sejam sempre compatíveis.
- Elimina o acoplamento entre o código cliente e as classes concretas.
- Concentra a criação em um só lugar (Princípio da Responsabilidade Única).
- Adicionar uma nova família não exige tocar no cliente (Aberto/Fechado).
- Muitas interfaces e classes novas — só compensa se houver famílias de verdade.
- Adicionar um novo TIPO de produto obriga a alterar a interface da fábrica e TODAS as fábricas concretas.
- Seu sistema precisa funcionar com várias famílias de produtos e você quer poder trocar a família inteira.
- Você quer impedir, por construção, que peças incompatíveis sejam combinadas.
- Você tem uma classe com um monte de Factory Methods que já estão obscurecendo sua responsabilidade principal.
- Existe só uma família e nenhuma perspectiva realista de uma segunda.
- Os produtos não têm relação entre si — aí você quer Factory Methods separados, não uma família.
Relações com outros padrões
- Factory Method
- Uma Abstract Factory costuma ser um conjunto de Factory Methods. É a evolução natural quando aparece a segunda família.
- Prototype
- A fábrica concreta pode clonar protótipos em vez de dar `new`.
- Builder
- Abstract Factory devolve o produto pronto de imediato; Builder monta passo a passo.
Verificação
Qual é o principal problema que Abstract Factory resolve e que Factory Method sozinho não resolve?
- Garantir que objetos criados em conjunto sejam de uma mesma família compatível
- Garantir que exista apenas uma instância de cada objeto
- Permitir clonar objetos existentes em vez de criá-los do zero
- Montar um objeto complexo em várias etapas configuráveis
Factory Method cria UM produto. Abstract Factory cria uma FAMÍLIA e, por construção, impede que você misture um botão macOS com um checkbox Windows.