Índice do grimório

Padrão 01 · Criacionais

Factory Method

variar a criação do mensageiro mantendo a operação comum de envio.

Começar pelo código
Uma enguia de água azul e placas de sal rompe o cais enquanto Talo alcança o posto com o tubo de despacho.
Cena do capítulo 01 · Factory Method

01 · Entenda a escolha

Os fundamentos do padrão.

README.md

01 — Factory Method: Mensageiros da guilda

Uma rotina de envio precisa continuar válida quando a criação do mensageiro muda. O projeto demonstra o Factory Method canônico: subclasses sobrescrevem criarMensageiro(), e CriadorDeNotificacoes.enviar() usa o produto por meio da interface Mensageiro.

Executar isoladamente

Requer Node 26.10.0 e npm 11.19.1 (se houver nvm: nvm use). Dentro deste diretório:

npm ci --ignore-scripts
npm test
npm start
npm run solution

npm test limpa dist, compila fontes/testes/solução com TypeScript estrito e executa node:test. exercise/ fica fora do build, separado da resposta. Nenhum outro capítulo é importado.

Arquivos e responsabilidades

  • src/contratos.ts: pedido, comprovante, produto e porta de correio.
  • src/criadores.ts: Creator, operação comum e Concrete Creators.
  • src/mensageiros.ts: Concrete Products.
  • src/correio-em-memoria.ts: simulador local com histórico observável.
  • src/cliente.ts: cliente que depende do criador abstrato.
  • src/main.ts: composição e demonstração.
  • test/: preservação do contrato, limites e falha do correio.
  • exercise/README.md: enunciado e critérios.
  • solution/: extensão de corvo, execução e testes.
  • diagram.mmd: relações editáveis correspondentes ao código-base.
  • evidence/: saídas reais, resultados e manifesto SHA-256.

Contrato e limites

enviar() remove espaços externos de destino e mensagem, rejeita strings vazias e só então cria um mensageiro. Um envio válido gera exatamente um registro local. O comprovante e a lista consultada não expõem mutação do histórico interno. Uma falha do correio é propagada; não há fallback automático nem retentativa.

O correio é síncrono, local e em memória: registro não significa recebimento por pessoa, transporte de rede, persistência, criptografia ou confirmação remota. IDs são sequenciais por instância, não globais. Os parâmetros têm tipos estáticos; a aplicação não valida JSON arbitrário nem é uma API pública pronta para produção. TypeScript não tem final: não sobrescrever enviar() é contrato de extensão, não bloqueio da linguagem.

Alternativa e custo

Se só for preciso escolher um rótulo de canal, uma função como correio.entregar(canal, pedido) resolve com menos classes. A hierarquia serve aqui para estudar uma operação herdada cujo ponto de criação varia, com produtos substituíveis. Adiciona classes, arquivos e acoplamento por herança. O exemplo reduz os transportes ao mínimo para observar o mecanismo, sem alegar que uma hierarquia se paga neste simulador.

Uma Simple Factory centralizaria uma escolha de produto (por exemplo, em uma função com discriminador). Aqui a operação chama um método sobrescrito pelas subclasses. Abstract Factory trata de famílias de produtos relacionados; não se distingue apenas pela quantidade de objetos produzidos.

O exercício amplia os canais sem editar a operação comum. A solução de corvo continua uma simulação; não mede latência nem capacidade de transporte.

02 · Leia o mecanismo

O feitiço, linha por linha.

Comece por src/main.ts para ver o programa em uso. Explore os contratos, a implementação e os testes no seletor de arquivos.

src/main.tsTypeScript
import { avisarGuilda } from "./cliente.js";
import { CorreioEmMemoria } from "./correio-em-memoria.js";
import { CriadorDeCristal, CriadorDePergaminho } from "./criadores.js";

const correio = new CorreioEmMemoria();
const pedido = {
  destino: "Posto da Ponte",
  mensagem: "Fechem a comporta antes da terceira badalada.",
};

// Ponto de composição: aqui se escolhem os criadores concretos.
for (const criador of [new CriadorDeCristal(correio), new CriadorDePergaminho(correio)]) {
  const recibo = avisarGuilda(criador, pedido);
  console.log(`#${recibo.id} | ${recibo.canal} | ${recibo.destino} | ${recibo.mensagem}`);
}
console.log(`Entregas registradas: ${correio.listarEntregas().length}`);
A execução do programa é feita localmente.

03 · Revele as conexões

A estrutura por trás da magia.

Veja os papéis e suas relações. Amplie cada vista para ler atributos, métodos e conexões com calma.

CriadorDeCristal herda de CriadorDeNotificacoes.
01 · a criação

Esta vista reúne CriadorDeNotificacoes, CriadorDeCristal, CriadorDePergaminho, Mensageiro. CriadorDeCristal herda de CriadorDeNotificacoes. CriadorDePergaminho herda de CriadorDeNotificacoes. CriadorDeNotificacoes depende de Mensageiro (enviar usa produto). CriadorDeNotificacoes: enviar valida e normaliza; chama criarMensageiro; delega entregar. Membros exibidos são um recorte; construtores e demais membros podem estar omitidos. e5 · enviar usa produto

MensageiroDeCristal realiza Mensageiro.
01 · b produtos

Esta vista reúne CriadorDeCristal, CriadorDePergaminho, Mensageiro, MensageiroDeCristal, MensageiroDePergaminho. MensageiroDeCristal realiza Mensageiro. MensageiroDePergaminho realiza Mensageiro. CriadorDeCristal depende de MensageiroDeCristal (cria). CriadorDePergaminho depende de MensageiroDePergaminho (cria). Membros exibidos são um recorte; construtores e demais membros podem estar omitidos. e6 · cria e7 · cria

MensageiroDeCristal mantém referência a Correio.
01 · c correio

Esta vista reúne CriadorDeNotificacoes, MensageiroDeCristal, MensageiroDePergaminho, Correio, CorreioEmMemoria. MensageiroDeCristal mantém referência a Correio. MensageiroDePergaminho mantém referência a Correio. CriadorDeNotificacoes mantém referência a Correio. CorreioEmMemoria realiza Correio. Membros exibidos são um recorte; construtores e demais membros podem estar omitidos.

04 · Faça sua escolha

Sua vez de conjurar.

exercise/README.md

Exercício — O canal de corvo

Implemente MensageiroDeCorvo e CriadorDeCorvo em arquivos novos. O produto deve implementar Mensageiro; o criador deve estender CriadorDeNotificacoes e sobrescrever somente criarMensageiro().

Critérios verificáveis:

  • avisarGuilda() continua idêntica e recebe o novo criador.
  • Um envio válido aparece no correio com canal corvo, destino e mensagem corretos.
  • Espaços externos são removidos pela operação comum herdada.
  • Destino ou mensagem vazios lançam o erro existente e não geram entrega.
  • Nenhum switch, parâmetro discriminador ou alteração em src/criadores.ts é necessário.

Compare sua solução com ../solution/corvo.ts e os testes em ../solution/corvo.test.ts. Para praticar, mantenha seus arquivos em exercise/ e compile com uma configuração própria: esse diretório não participa do build oficial, evitando colisões com a resposta.

A solução usa herança para variar a criação, preservando a operação. Se o problema fosse apenas escolher um rótulo de canal, passar esse rótulo a uma função seria suficiente; a hierarquia aqui torna explícito o mecanismo do Factory Method, sem afirmar que é necessária para todo sistema de mensagens.

Compare depois da sua tentativa.

A resposta e seus testes estão na pasta solution/. O sucesso dos testes fornecidos confirma essa resposta; sua tentativa precisa estar incluída na compilação para ser avaliada.

Do estudo à prática

Experimente localmente.

Node 26.10.0 · npm 11.19.1 · TypeScript 5.9.3

Execute os comandos dentro da pasta deste projeto. O lock instala o compilador local. Os programas não são executados no navegador.

cd book-23/code/01-factory-method
npm ci --ignore-scripts --no-audit --no-fund
npm test
npm start

# Depois da sua tentativa
npm run solution
Baixar este projeto completo

Diagrama ampliado