Factory Method
Visão Geral
Factory Method define uma operação de criação numa classe base e deixa as subclasses decidirem qual objeto concreto instanciar.
O problema que ele resolve é específico: uma classe precisa criar objetos cujo tipo concreto ela não conhece. Se você conhece o tipo, não precisa do padrão.
Problema
Um framework define o esqueleto de um processo e precisa criar objetos ao longo dele — mas os objetos concretos pertencem a quem usa o framework, e o framework não pode conhecê-los.
O exemplo canônico é um editor de documentos que sabe abrir, salvar e fechar
documentos, sem saber se o documento é de texto, planilha ou desenho. A operação
criarDocumento() é abstrata; cada especialização do editor a implementa.
Note a assimetria: o padrão existe para o caso em que quem chama a criação não pode conhecer o que está sendo criado. Fora dessa condição, ele é indireção.
Conceitos Centrais
A estrutura
operacao() usa criarProduto() sem saber o que ela devolve. A subclasse decide.
A dependência da herança
Factory Method usa herança para variar a criação. Isso o amarra aos custos de herança: um eixo de variação, acoplamento à implementação da base, e uma classe nova para cada tipo de produto. Ver composição vs. herança.
Em linguagens com funções de primeira classe, passar uma função de criação resolve o mesmo problema sem hierarquia — e é por isso que o padrão aparece com menos frequência em código funcional e em linguagens modernas.
Não confunda com "método estático que cria objeto"
A maior parte do que se chama de "factory" no dia a dia é uma função de fábrica ou um static factory method — um método nomeado que constrói e devolve um objeto.
Isso é útil e não é o padrão. A função de fábrica melhora legibilidade
(Cor.deHex("#1f4e79") diz mais que um construtor) e permite cache ou validação.
Factory Method resolve outro problema: variação de tipo decidida por subclasse.
Confundir os dois leva a criar hierarquias onde uma função bastaria.
Quando Usar
- Um framework precisa criar objetos que o cliente define.
- A classe base implementa um processo e as subclasses variam apenas o que é criado ao longo dele.
- O conjunto de tipos de produto cresce por extensão, e você não pode alterar a classe base a cada novo tipo.
Quando Não Usar
Quando você conhece o tipo concreto. Chame o construtor.
Quando uma função de fábrica resolve. Se a variação não precisa ser decidida por subclasse, passar uma função de criação é mais simples e mais flexível — pode mudar em execução, e não exige hierarquia.
Quando há uma única implementação. Ver YAGNI. Uma hierarquia de criadores com um criador concreto é indireção pura.
Quando o eixo de variação é mais de um. Herança amarra a um; dois eixos produzem explosão combinatória. Componha.
Em linguagens com construtores flexíveis. Onde é possível passar a função de criação, o padrão perde a razão de existir.
Alternativas
- Função de fábrica — a resposta na maioria dos casos.
- Função como parâmetro — passar
() -> Produtoem vez de herdar. - Abstract Factory — quando são famílias de produtos relacionados, não um.
- Injeção de dependência — receber o objeto pronto em vez de criá-lo.
Trade-offs
| Factory Method | Construtor direto |
|---|---|
| Cliente desacoplado do tipo concreto | Cliente conhece o tipo |
| Extensão por nova subclasse | Extensão altera o cliente |
| Uma hierarquia paralela a manter | Sem hierarquia |
| Um eixo de variação | Sem restrição |
| Fluxo indireto | Direto |
Modos de Falha
Hierarquia paralela. Cada produto novo exige um criador novo. Duas hierarquias crescendo juntas.
Criador único. O padrão aplicado sem segunda subclasse.
Confusão com função de fábrica. Hierarquia criada onde um método estático bastava.
Erros Comuns
Chamar qualquer método de criação de "factory method". A maior parte não é o padrão.
Aplicar quando o tipo é conhecido. Indireção sem ganho.
Usar herança onde uma função resolveria.
Criar a hierarquia antes do segundo produto. Espere a variação existir.
Exemplo Real
Uma biblioteca de exportação de relatórios definia Exportador com o processo —
validar, transformar, escrever, finalizar — e criarEscritor() abstrato. Cada
formato tinha sua subclasse.
Funcionou bem enquanto havia três formatos.
O problema apareceu quando surgiu um segundo eixo: destino. O mesmo formato podia ir para arquivo local, armazenamento de objetos ou fluxo de resposta HTTP. A hierarquia teria nove classes.
A reformulação substituiu a herança por composição: Exportador(formatador, destino). Três formatadores e três destinos, combináveis.
O que vale reter: Factory Method estava correto para o problema original. Ele deixou de servir quando um segundo eixo apareceu — que é exatamente a limitação declarada em "quando não usar".
Onde ele aparece na prática
Reconhecer o padrão em bibliotecas conhecidas ajuda mais que qualquer diagrama.
Coleções de Java. Collection.iterator() é Factory Method: a interface
declara a operação, cada implementação concreta decide qual iterador devolver, e
quem consome não sabe nem precisa saber.
Frameworks de teste. O ciclo de vida define quando criar a instância de teste; a subclasse ou a anotação decide qual.
Conexões de banco. DriverManager.getConnection seleciona a implementação
concreta a partir da URL — variação de tipo decidida em outro lugar que não o
chamador.
O que esses três compartilham: quem chama está dentro de uma biblioteca que não pode conhecer as classes concretas de quem a usa. É a condição que justifica o padrão, e a ausência dela num sistema de aplicação é a razão pela qual ele raramente se justifica ali.
Num sistema de negócio típico, você conhece os tipos concretos. É a diferença entre escrever um framework e escrever uma aplicação — e boa parte do uso indevido de padrões vem de aplicar a segunda o que foi projetado para a primeira.
Conceitos Relacionados
- Abstract Factory — famílias de produtos.
- Builder — construção em etapas.
- Template Method — a mesma mecânica de herança aplicada ao processo inteiro.
- Composição vs. Herança.
Exercício Prático
Procure no seu sistema classes cujo nome termina em Factory. Para cada uma,
verifique: ela usa herança para variar o tipo criado, ou é um método nomeado que
constrói?
As do segundo tipo são funções de fábrica. Confirme se alguém as chama de padrão sem que sejam.
Perguntas de Entrevista
- Qual a diferença entre Factory Method e uma função de fábrica?
- Que limitação a dependência de herança impõe a este padrão?
- Quando uma função passada como parâmetro é preferível?
Para Aprofundar
- Gamma, Erich et al. Design Patterns. Addison-Wesley, 1994.
- Bloch, Joshua. Effective Java. 3ª ed., 2018 — sobre static factory methods, que não são este padrão.