Pular para o conteúdo
GoF Padrões de Projeto Criacionais
Criacional escopo de classe
GoF, p. 107 também chamado de Virtual Constructor

Método Fábrica

Factory Method

A superclasse define o esqueleto; a subclasse decide qual objeto criar.

Complexidade simples Frequência de uso muito comum
Intençãocomo o livro define

Definir uma interface para criar um objeto, mas deixar as subclasses decidirem qual classe instanciar. Factory Method permite que uma classe adie a instanciação para subclasses.

Analogiauma imagem do mundo real

A transportadora

Sua empresa começou só com caminhões: toda a logística estava escrita em cima da classe Caminhão. Aí chegou o transporte marítimo. Reescrever tudo com `if (é navio)` seria um pesadelo. Em vez disso, a logística passa a pedir “me dê um transporte” a um método que as subclasses sobrescrevem: LogísticaTerrestre devolve Caminhão, LogísticaMarítima devolve Navio. O roteiro de entrega continua idêntico.

O problema

Uma classe precisa criar objetos, mas não deve (ou não pode) saber de antemão qual classe concreta será. Chamar `new ClasseConcreta()` direto no meio da lógica prende o código a ela para sempre.

A solução

Substitua as chamadas diretas a `new` por chamadas a um método fábrica sobrescrevível. A superclasse programa contra a interface do produto; cada subclasse retorna a variante que lhe cabe.

Sintomascomo reconhecer no seu código
  • switch (tipo) { case "pdf": return new PDF(); ... } repetido em vários lugares.
  • new de classe concreta dentro de uma classe de alto nível.

Estrutura

usacriacria«abstrata»Logistica+ criarTransporte()*+ planejarEntrega()LogisticaTerrestre+ criarTransporte()LogisticaMaritima+ criarTransporte()«interface»Transporte+ entregar()CaminhaoNavio
Fig. 3 — Factory Method herda / implementa cria usa / contém
Ver este diagrama sendo desenhado, traço a traço
Participantes
Product
Interface comum a tudo que o método fábrica pode retornar.
ConcreteProduct
Implementações específicas do produto.
Creator
Declara o método fábrica e contém a lógica de negócio que usa o produto.
ConcreteCreator
Sobrescreve o método fábrica para devolver um produto concreto.

Implementação

Listagem 3 Exportadores de relatório: mesma lógica, formatos diferentes
// ── Produto ───────────────────────────────────────────
class Documento {
  serializar(dados) { throw new Error('abstrato'); }
  get extensao()    { throw new Error('abstrato'); }
}
class DocCSV  extends Documento {
  serializar(d)  { return d.map(l => Object.values(l).join(',')).join('\n'); }
  get extensao() { return 'csv'; }
}
class DocJSON extends Documento {
  serializar(d)  { return JSON.stringify(d, null, 2); }
  get extensao() { return 'json'; }
}

// ── Creator: a lógica de negócio vive AQUI, uma vez só ─
class Exportador {
  // ↓ o Factory Method. As subclasses respondem a esta pergunta.
  criarDocumento() { throw new Error('subclasse deve implementar'); }

  // Este método NUNCA muda quando surge um novo formato.
  exportar(dados) {
    const doc = this.criarDocumento();
    const conteudo = doc.serializar(dados);
    return { nome: `relatorio.${doc.extensao}`, bytes: conteudo.length, conteudo };
  }
}

class ExportadorCSV  extends Exportador { criarDocumento() { return new DocCSV(); } }
class ExportadorJSON extends Exportador { criarDocumento() { return new DocJSON(); } }

const dados = [{ id: 1, nome: 'Ana' }, { id: 2, nome: 'Bruno' }];
console.log(new ExportadorCSV().exportar(dados).nome);   // relatorio.csv
console.log(new ExportadorJSON().exportar(dados).nome);  // relatorio.json
Na práticaonde ele já existe
  • java.util.Calendar.getInstance()
  • java.net.URLStreamHandlerFactory
  • React.createElement — a raiz de todo componente

Consequências

A favor
  • Elimina o acoplamento entre o criador e os produtos concretos.
  • Centraliza a criação num único ponto, fácil de estender.
  • Novos produtos entram sem tocar no código existente (Aberto/Fechado).
Contra
  • Pode gerar muitas subclasses só para variar a criação.
  • Introduz uma hierarquia paralela (creators espelhando products).
Use quando
  • Você não sabe de antemão os tipos exatos com que seu código vai trabalhar.
  • Você quer dar aos usuários da sua biblioteca um jeito de estender seus componentes internos.
  • Você quer reaproveitar objetos caros em vez de recriá-los (o método fábrica pode devolver de um pool).
Evite quando
  • Só existe um tipo de produto e não há sinal de um segundo.
  • Uma função simples que recebe o tipo por parâmetro já resolve (a “simple factory”, que não é GoF).

Relações com outros padrões

evolui para
Abstract Factory
Abstract Factory é frequentemente um conjunto de Factory Methods.
costuma andar junto
Template Method
Factory Method costuma ser uma etapa dentro de um Template Method.
Iterator
Uma coleção usa um Factory Method para devolver o iterador adequado.
alternativa a
Prototype
Prototype não exige subclasses, mas exige inicialização do protótipo.

Verificação

Questãoa resposta está marcada

Qual afirmação distingue corretamente Factory Method de Abstract Factory?

  1. Factory Method cria UM produto via herança; Abstract Factory cria uma FAMÍLIA via composição
  2. Factory Method é mais lento porque usa reflexão
  3. Abstract Factory só funciona com objetos imutáveis
  4. Factory Method exige uma classe Director

Factory Method é um padrão de escopo de CLASSE (usa herança: a subclasse decide). Abstract Factory é de escopo de OBJETO (o cliente recebe uma fábrica por composição).