Pular para o conteúdo principal

Factory Method

Descrição​

O Factory Method define uma interface para criar um objeto, mas deixa que as subclasses decidam qual classe concreta instanciar. Em vez de chamar o construtor diretamente, a classe base (o Creator) declara um método de fábrica — geralmente abstrato ou com uma implementação padrão — que retorna um Product abstrato.

O ponto central é que o Creator normalmente contém lógica de negócio que usa o produto, sem saber qual implementação concreta está sendo usada. Cada subclasse (ConcreteCreator) sobrescreve o método de fábrica para devolver o ConcreteProduct adequado. Assim, a criação é adiada para as subclasses e o código cliente depende apenas de abstrações.

Diferente da Factory (Simple Factory), que é um único método/classe com condicionais (if/switch) decidindo o que criar, o Factory Method usa herança e polimorfismo: cada variante de criação vive em uma subclasse. Já o Abstract Factory cria famílias de produtos relacionados por meio de vários métodos de criação em um objeto de fábrica (composição), enquanto o Factory Method trata de um produto por método.

Problemas que resolve​

  • Código que instancia classes concretas diretamente (new) fica acoplado a implementações e precisa ser alterado a cada novo tipo.
  • Um framework ou biblioteca precisa permitir que os usuários estendam os objetos que ele cria internamente.
  • Lógica comum (fluxo, validação, ciclo de vida) se repete entre variantes que diferem apenas no objeto criado.
  • Condicionais de criação espalhados pelo código violam o princípio Open/Closed.

Quando usar​

  • Quando a classe não sabe de antemão quais tipos exatos de objetos precisa criar.
  • Quando se deseja que subclasses especifiquem os objetos criados, como em frameworks e pontos de extensão.
  • Quando há um algoritmo comum na classe base e apenas o produto varia (combina bem com Template Method).
  • Quando se quer reaproveitar objetos existentes (cache, pool) por trás de um método de criação, em vez de sempre construir novos.

Quando evitar​

  • Quando há apenas um tipo de produto e não há perspectiva real de variação — um construtor simples basta.
  • Quando a criação de subclasses só para trocar o produto gera uma explosão de classes; uma Simple Factory, injeção de dependência ou uma função/lambda de criação pode ser mais simples.
  • Quando é preciso criar famílias de objetos que devem ser compatíveis entre si — prefira Abstract Factory.

Trade-offs​

GanhoCusto / Risco
Desacopla o Creator dos produtos concretosExige uma hierarquia paralela de Creators e Products
Novos produtos sem alterar código existente (Open/Closed)Mais classes e indireção para entender o fluxo
Centraliza a criação em um único ponto (Single Responsibility)Baseado em herança: menos flexível que composição em tempo de execução
Facilita testes substituindo o produto por um fake via subclassePode ser overengineering em cenários simples
  • Acoplamento: o cliente depende apenas de Creator e Product abstratos.
  • Testabilidade: basta uma subclasse de teste que sobrescreva o método de fábrica.
  • Complexidade: cresce com o número de variantes; avalie se uma Simple Factory resolve.
  • Evolução: é comum começar com Factory Method e evoluir para Abstract Factory, Prototype ou Builder conforme a necessidade de flexibilidade aumenta.

Diagrama​

O Creator declara o método abstrato createProduct() e usa o Product em someOperation(). Cada ConcreteCreator sobrescreve o método de fábrica para instanciar seu ConcreteProduct correspondente, sem que o Creator conheça a classe concreta.

Exemplo​

Um serviço de notificações tem um fluxo comum (montar a mensagem, enviar, registrar log), mas o canal varia: e-mail ou SMS. Cada subclasse decide qual Notifier criar.

interface Notifier {
send(to: string, message: string): void;
}

class EmailNotifier implements Notifier {
send(to: string, message: string) { console.log(`Email para ${to}: ${message}`); }
}

class SmsNotifier implements Notifier {
send(to: string, message: string) { console.log(`SMS para ${to}: ${message}`); }
}

abstract class NotificationService {
protected abstract createNotifier(): Notifier; // Factory Method

notify(to: string, message: string): void {
const notifier = this.createNotifier();
notifier.send(to, message);
console.log(`log: notificação enviada para ${to}`);
}
}

class EmailNotificationService extends NotificationService {
protected createNotifier(): Notifier { return new EmailNotifier(); }
}

class SmsNotificationService extends NotificationService {
protected createNotifier(): Notifier { return new SmsNotifier(); }
}

const service: NotificationService = new SmsNotificationService();
service.notify("+5511999999999", "Seu pedido foi enviado");

Padrões relacionados​

  • Factory — a Simple Factory concentra a decisão em um único método com condicionais; o Factory Method distribui essa decisão entre subclasses via polimorfismo, evitando modificar a fábrica a cada novo tipo.
  • Abstract Factory — cria famílias de produtos relacionados por composição; suas fábricas concretas costumam ser implementadas com um Factory Method por produto.
  • Template Method — o Factory Method é frequentemente um passo de um Template Method, em que a classe base define o algoritmo e a subclasse fornece o objeto.
  • Prototype — alternativa que cria objetos clonando instâncias, sem exigir uma hierarquia de Creators.
  • Builder — foca na construção passo a passo de objetos complexos, enquanto o Factory Method decide qual classe instanciar.
  • Iterator — coleções usam um Factory Method (createIterator()) para devolver o iterador compatível com sua estrutura.

Referência​