GoF, p. 325
Método Modelo
Template Method
A superclasse fixa o esqueleto; as subclasses preenchem os buracos.
Definir o esqueleto de um algoritmo em uma operação, postergando alguns passos para as subclasses. Template Method permite que subclasses redefinam certos passos de um algoritmo sem mudar sua estrutura.
A planta padrão do condomínio
Todas as casas do condomínio seguem a mesma planta: fundação, estrutura, paredes, telhado, acabamento — nessa ordem, sempre. O comprador escolhe o acabamento e o material das paredes. A sequência das etapas é imutável; o conteúdo de algumas delas, não.
Vários processos seguem exatamente a mesma sequência de etapas, diferindo apenas em algumas delas. O resultado é código quase duplicado entre classes, com a estrutura repetida por toda parte.
Quebre o algoritmo em etapas. Coloque na superclasse um método `template` que chama as etapas na ordem correta e é declarado final. Etapas comuns ganham implementação padrão; as que variam viram abstratas ou “hooks” opcionais.
- Três classes com o mesmo método, diferindo em duas linhas.
- Copiar e colar uma sequência de etapas para criar uma variante.
Estrutura
- AbstractClass
- Define o método template (a ordem fixa) e declara as etapas.
- ConcreteClass
- Implementa as etapas abstratas e, opcionalmente, sobrescreve hooks.
- Hook
- Etapa com implementação vazia/padrão que a subclasse pode ou não sobrescrever.
Implementação
class ImportadorDeDados {
// ── O TEMPLATE METHOD: a ordem é lei, ninguém sobrescreve ──
importar(caminho) {
const bruto = this.ler(caminho); // ① abstrato
const registros = this.analisar(bruto); // ② abstrato
const validos = registros.filter(r => this.validar(r)); // ③ padrão, sobrescrevível
const finais = validos.map(r => this.transformar(r)); // ④ hook (identidade)
this.persistir(finais); // ⑤ padrão
this.aoConcluir(finais); // ⑥ hook (vazio)
return { lidos: registros.length, importados: finais.length };
}
// ── Etapas OBRIGATÓRIAS (abstratas) ─────────────────
ler(caminho) { throw new Error('subclasse deve implementar ler()'); }
analisar(bruto) { throw new Error('subclasse deve implementar analisar()'); }
// ── Etapas com PADRÃO (podem ser sobrescritas) ──────
validar(r) { return r != null && Object.keys(r).length > 0; }
persistir(rs) { console.log(`💾 gravando ${rs.length} registros`); }
// ── HOOKS: existem só para serem opcionalmente estendidos ──
transformar(r) { return r; }
aoConcluir(rs) { /* vazio de propósito */ }
}
class ImportadorCSV extends ImportadorDeDados {
ler(c) { return 'nome,idade\nAna,30\nBruno,\nCarla,41'; }
analisar(txt) {
const [cab, ...linhas] = txt.split('\n');
const cols = cab.split(',');
return linhas.map(l => Object.fromEntries(l.split(',').map((v, i) => [cols[i], v])));
}
validar(r) { return super.validar(r) && r.idade !== ''; } // estende o padrão
transformar(r){ return { ...r, idade: Number(r.idade) }; }
}
class ImportadorJSON extends ImportadorDeDados {
ler(c) { return '[{"nome":"Dan","idade":22}]'; }
analisar(txt) { return JSON.parse(txt); }
aoConcluir(rs){ console.log('📣 webhook disparado'); } // usa o hook
}
console.log(new ImportadorCSV().importar('x.csv')); // { lidos: 3, importados: 2 }
console.log(new ImportadorJSON().importar('x.json')); // 📣 webhook … { lidos: 1, importados: 1 } - java.util.AbstractList / AbstractMap
- javax.servlet.http.HttpServlet — doGet, doPost são hooks
- Métodos de ciclo de vida de frameworks (setUp/tearDown de testes)
Consequências
- Elimina duplicação: a estrutura do algoritmo existe uma vez só.
- Deixa os clientes sobrescrever apenas partes bem definidas.
- A ordem das etapas fica protegida contra alterações acidentais.
- Limita a flexibilidade ao esqueleto pré-definido.
- Viola o Princípio de Substituição de Liskov se uma subclasse suprimir uma etapa padrão.
- Quanto mais etapas, mais difícil de manter.
- Herança acopla fortemente: a subclasse depende de detalhes internos da superclasse.
- Clientes precisam estender só partes específicas de um algoritmo, não sua estrutura.
- Várias classes têm algoritmos quase idênticos, com pequenas diferenças.
- Você precisa trocar o algoritmo inteiro em tempo de execução — use Strategy.
- A hierarquia de herança já está profunda demais.
Relações com outros padrões
- Strategy
- Template Method: herança, em tempo de compilação, partes do algoritmo. Strategy: composição, em tempo de execução, o algoritmo todo.
- Factory Method
- Factory Method é frequentemente uma etapa dentro de um Template Method.
- Builder
- Ambos definem uma sequência de etapas; Builder usa composição, Template Method usa herança.
Verificação
O que é um “hook” em Template Method?
- Uma etapa com implementação vazia ou padrão, que a subclasse pode sobrescrever mas não precisa
- Um método que a subclasse é obrigada a implementar
- Um callback registrado em tempo de execução
- O método que define a ordem das etapas
Hooks são pontos de extensão opcionais. Etapas abstratas são obrigatórias; o método template é o que define a ordem e normalmente é final.