Padrão de Projeto: Factory Method
Propósito
O Factory Method é um padrão criacional de projeto que fornece uma interface para criar objetos em uma superclasse, mas permite que as subclasses alterem o tipo de objetos que serão criados.
Problema
Imagine que você está criando uma aplicação de gerenciamento de logística. Inicialmente, a aplicação lida apenas com transporte de caminhões, e a maior parte do código está na classe Caminhão. Com o tempo, a aplicação se torna popular e você recebe solicitações para incorporar logística marítima. Adicionar uma nova classe Navio exigiria alterações em toda a base de código, resultando em um código sujo e cheio de condicionais.
Solução
O padrão Factory Method sugere substituir chamadas diretas de construção de objetos (usando o operador new) por chamadas para um método fábrica especial. As subclasses podem alterar a classe de objetos retornados pelo método fábrica, desde que todos os produtos implementem uma interface comum.
Estrutura
- Produto: Declara a interface, que é comum a todos os objetos que podem ser produzidos pelo criador e suas subclasses.
- Produtos Concretos: Implementações diferentes da interface do produto.
- Criador: Declara o método fábrica que retorna novos objetos produto.
- Criadores Concretos: Sobrescrevem o método fábrica base para retornar um tipo diferente de produto.
Exemplo em PHP
Interface Produto
interface Transporte {
public function entregar();
}Produtos Concretos
class Caminhão implements Transporte {
public function entregar() {
echo "Entrega por terra em uma caixa.\n";
}
}
class Navio implements Transporte {
public function entregar() {
echo "Entrega por mar em um contêiner.\n";
}
}Criador
abstract class Logistica {
// O método fábrica
abstract public function criarTransporte(): Transporte;
public function planearEntrega() {
$transporte = $this->criarTransporte();
$transporte->entregar();
}
}Criadores Concretos
class LogisticaRodoviaria extends Logistica {
public function criarTransporte(): Transporte {
return new Caminhão();
}
}
class LogisticaMaritima extends Logistica {
public function criarTransporte(): Transporte {
return new Navio();
}
}Código Cliente
function clientCode(Logistica $logistica) {
$logistica->planearEntrega();
}
echo "App: Planejamento de entrega por terra:\n";
clientCode(new LogisticaRodoviaria());
echo "\nApp: Planejamento de entrega por mar:\n";
clientCode(new LogisticaMaritima());Exemplo em Node.js
Interface Produto
class Transporte {
entregar() {
throw new Error("Método 'entregar()' deve ser implementado.");
}
}Produtos Concretos
class Caminhao extends Transporte {
entregar() {
console.log("Entrega por terra em uma caixa.");
}
}
class Navio extends Transporte {
entregar() {
console.log("Entrega por mar em um contêiner.");
}
}Criador
class Logistica {
// O método fábrica
criarTransporte() {
throw new Error("Método 'criarTransporte()' deve ser implementado.");
}
planearEntrega() {
const transporte = this.criarTransporte();
transporte.entregar();
}
}Criadores Concretos
class LogisticaRodoviaria extends Logistica {
criarTransporte() {
return new Caminhao();
}
}
class LogisticaMaritima extends Logistica {
criarTransporte() {
return new Navio();
}
}Código Cliente
function clientCode(logistica) {
logistica.planearEntrega();
}
console.log("App: Planejamento de entrega por terra:");
clientCode(new LogisticaRodoviaria());
console.log("\nApp: Planejamento de entrega por mar:");
clientCode(new LogisticaMaritima());Aplicabilidade
- Use o Factory Method quando não souber de antemão os tipos e dependências exatas dos objetos com os quais seu código deve funcionar.
- Use o Factory Method quando desejar fornecer aos usuários da sua biblioteca ou framework uma maneira de estender seus componentes internos.
- Use o Factory Method quando deseja economizar recursos do sistema reutilizando objetos existentes em vez de recriá-los sempre.
Prós e Contras
Prós
- Evita acoplamentos firmes entre o criador e os produtos concretos.
- Princípio de responsabilidade única: facilita a manutenção do código.
- Princípio aberto/fechado: permite introduzir novos tipos de produtos sem quebrar o código cliente existente.
Contras
- Pode tornar o código mais complicado devido à introdução de muitas subclasses novas.
Relações com outros padrões
- Muitos projetos começam usando o Factory Method e evoluem para o Abstract Factory, Prototype, ou Builder.
- Classes Abstract Factory são quase sempre baseadas em um conjunto de métodos fábrica.
- Você pode usar o Factory Method junto com o Iterator para permitir que uma coleção de subclasses retornem diferentes tipos de iteradores.
- O Factory Method é uma especialização do Template Method.
Este guia fornece uma visão abrangente do padrão Factory Method, ilustrando sua aplicação com exemplos em PHP e Node.js. Ele é essencial para criar sistemas flexíveis e extensíveis, permitindo a criação de objetos de maneira desacoplada e seguindo os princípios de design orientado a objetos.