Conceito Fundamental
O Factory Method (Método Fábrica) é um padrão criacional que define uma assinatura para a construção de objetos, delegando às subclasses a responsabilidade de escohler qual classe concreta será materializada. Essa estratégia posterga a vinculação direta com tipos específicos até a execução, permitindo que a estrutura principal permaneça estável enquanto novas variantes são introduzidas.
Diferente de uma fábrica monolítica que concentra todas as regras de instanciação, este modelo fragmenta a criação. Cada subclasse da fábrica assume a obrigação de proudzir um único tipo de derivado, alinhando-se diretamente ao princípio da responsabilidade única e facilitando a manutenção do código.
Componentes da Arquitetura
- Produto (Produto): Interface ou classe abstrata que estabelece o contrato comportamental dos objetos gerados pelo método fábrica.
- ProdutoConcreto: Implementações específicas que cumprem a interface definida no contrato de Produto.
- Criador (Criador): Classe abstrata ou interface que declara o método responsável pela instanciação. Pode conter métodos auxiliares que operam sobre o produto retornado, mantendo a lógica de fluxo de controle desacoplada dos detalhes de criação.
- CriadorConcreto: Subclasses que herdam ou implementam o Criador, sobrescrevendo o método fábrica para retornar a instância adequada do ProdutoConcreto correspondente.
Representação UML
classDiagram
class Produto {
<<Interface>>
+executarOperacao()
}
class ProdutoConcretoA {
+executarOperacao()
}
class ProdutoConcretoB {
+executarOperacao()
}
Produto <|.. ProdutoConcretoA
Produto <|.. ProdutoConcretoB
class Criador {
<<Abstract>>
+instanciarProduto(): Produto
+processarFluxo()
}
class CriadorConcretoA {
+instanciarProduto(): Produto
}
class CriadorConcretoB {
+instanciarProduto(): Produto
}
Criador <|-- CriadorConcretoA
Criador <|-- CriadorConcretoB
CriadorConcretoA ..> ProdutoConcretoA : cria
CriadorConcretoB ..> ProdutoConcretoB : cria
Cliente --> Criador
Cliente --> Produto
O método processarFluxo() na classe abstrata Criador tipicamente invoca instanciarProduto() para obter uma referência válida e, em seguida, executa as operações de domínio necessárias sobre esse objeto.
Análise de Vantagens e Limitações
Pontos Positivos:
- Conformidade com o Princípio Aberto/Fechado: A introdução de novas variantes exige apenas a criação de novas classes concretas, sem modificar a infraestrutura existente.
- Desacoplamento Efetivo: A lógica de consumo de objetos permanece independente dos mecanismos de instanciação. O cliente manipula apenas contratos abstratos.
- Extensibilidade Controlada: Subclasses podem redefinir o tipo de objeto retornado, garantindo que cada fábrica gerencie um domínio específico e previsível.
Restrições:
- Proliferação de Classes: Cada nova variante demanda a implementação de um produto concreto e sua respectiva fábrica, aumentando o volume de arquivos e a complexidade do projeto em cenários simples.
Contextos de Aplicação
- Quando uma classe desconhece antecipadamente os tipos exatos dos objetos que deve manipular.
- Quando a política de criação deve ser delegada e controlada por subclasses especializadas.
- Quando se deseja encapsular a seleção de implementações alternativas em módulos auxiliares, localizando a lógica de decisão.
Exemplo Prático em Java
O cenário abaixo modela um sistema de conversão de relatórios financeiros, onde diferentes formatos de saída (PDF ou CSV) são gerados dinamicamente com base na escolha do cliente.
public interface ExportadorFinanceiro {
String converter(Map<String, Double> dados);
String obterExtensao();
}
public class ExportadorPdf implements ExportadorFinanceiro {
@Override
public String converter(Map<String, Double> dados) {
StringBuilder buffer = new StringBuilder("%PDF-1.4\n%Relatorio Gerado\n");
dados.forEach((k, v) -> buffer.append(k).append(": ").append(v).append("\n"));
return buffer.toString();
}
@Override
public String obterExtensao() {
return ".pdf";
}
}
public class ExportadorCsv implements ExportadorFinanceiro {
@Override
public String converter(Map<String, Double> dados) {
StringBuilder buffer = new StringBuilder("Chave,Valor\n");
dados.forEach((k, v) -> buffer.append(k).append(",").append(v).append("\n"));
return buffer.toString();
}
@Override
public String obterExtensao() {
return ".csv";
}
}
public abstract class GeradorRelatorio {
public abstract ExportadorFinanceiro selecionarExportador();
public void executarExportacao(String titulo, Map<String, Double> valores) {
ExportadorFinanceiro exportador = selecionarExportador();
System.out.println("Inicializando exportação [" + exportador.obterExtensao() + "]");
String conteudo = exportador.converter(valores);
System.out.println("Conteúdo gerado para: " + titulo);
System.out.println(conteudo.split("\n")[0]); // Apenas cabeçalho para demonstração
}
}
public class GeradorPdf extends GeradorRelatorio {
@Override
public ExportadorFinanceiro selecionarExportador() {
System.out.println("Alocando recursos para PDF...");
return new ExportadorPdf();
}
}
public class GeradorCsv extends GeradorRelatorio {
@Override
public ExportadorFinanceiro selecionarExportador() {
System.out.println("Preparando estrutura CSV...");
return new ExportadorCsv();
}
}
Implementação do consumidor:
import java.util.HashMap;
import java.util.Map;
public class Aplicacao {
public static void main(String[] args) {
Map<String, Double> balanco = new HashMap<>();
balanco.put("Receita", 50000.00);
balanco.put("Despesas", 12000.00);
GeradorRelatorio fabricaPdf = new GeradorPdf();
fabricaPdf.executarExportacao("Balanco_Mensal", balanco);
System.out.println("---\n");
GeradorRelatorio fabricaCsv = new GeradorCsv();
fabricaCsv.executarExportacao("Balanco_Mensal_Detalhado", balanco);
// Para adicionar um novo formato (ex: XML), basta criar:
// 1. ExportadorXml implementando ExportadorFinanceiro
// 2. GeradorXml estendendo GeradorRelatorio
// A aplicação cliente permanece inalterada.
}
}
Saída gerada durante a execução:
Alocando recursos para PDF...
Inicializando exportação [.pdf]
Conteúdo gerado para: Balanco_Mensal
%PDF-1.4
---
Preparando estrutura CSV...
Inicializando exportação [.csv]
Conteúdo gerado para: Balanco_Mensal_Detalhado
Chave,Valor