Skip to main content

Template Method

Visão Geral

Template Method define o esqueleto de um algoritmo numa classe base, deixando etapas específicas para as subclasses.

É o padrão que mais depende de herança, e por isso o que mais frequentemente tem uma alternativa melhor em Strategy.

Problema

Vários processos compartilham a mesma estrutura e diferem em algumas etapas.

Importar dados: abrir a fonte, validar o formato, transformar, gravar, fechar. A sequência é sempre a mesma; validar e transformar dependem do formato.

Sem o padrão, cada importador repete a sequência inteira. Quando a sequência muda — acrescentar registro de auditoria entre transformar e gravar — todos precisam mudar, e alguém esquece.

Conceitos Centrais

A estrutura

classe base:
processar(): ← template, final
abrir()
validar() ← abstrato
transformar() ← abstrato
gravar()
fechar()

O método template é final: a subclasse não deve alterar a sequência, apenas preencher as lacunas. Permitir sobrescrever o template destrói a garantia que o padrão oferece.

Inversão de controle

A classe base chama a subclasse, não o contrário. É o princípio de Hollywood: "não nos chame, nós chamamos você".

Isso é a base de como frameworks funcionam, e é a razão pela qual o padrão aparece tanto em código de framework e tão pouco em código de aplicação.

Ganchos versus operações abstratas

Operação abstrata — a subclasse é obrigada a implementar. Gancho — tem implementação padrão vazia ou trivial; a subclasse pode sobrescrever.

Ganchos dão flexibilidade e criam um problema: quem lê a subclasse não sabe quais existem sem ler a base. Quanto mais ganchos, menos previsível o comportamento.

O custo da herança

Template Method herda todos os custos de herança de implementação: um eixo de variação, acoplamento à implementação da base, e o problema da classe base frágil — mudar a base quebra subclasses que ninguém tocou.

Strategy resolve o mesmo problema por composição, sem esses custos.

Quando Usar

  • A sequência é genuinamente fixa e deve ser garantida.
  • Existe um único eixo de variação.
  • A hierarquia é rasa e o conjunto de variantes é fechado.
  • Você está escrevendo um framework em que o usuário estende a base.

Quando Não Usar

Quando há mais de um eixo de variação. Explosão combinatória. Componha.

Quando as etapas variam independentemente. Se validar e transformar variam sem correlação, são duas estratégias, não uma subclasse.

Quando a variante precisa mudar em execução. Herança é fixa em compilação.

Quando há muitos ganchos. Uma base com dez ganchos é um contrato implícito que ninguém consegue reter.

Quando Strategy resolve. Que é a maioria dos casos em código de aplicação.

Alternativas

  • Strategy — composição no lugar da herança. A alternativa principal.
  • Funções passadas como parâmetroprocessar(validar, transformar).
  • Método template que recebe as etapas — sem hierarquia, o esqueleto vira uma função que aceita as variações.

Trade-offs

Template MethodStrategy
Sequência garantida na baseSequência a cargo de quem compõe
Menos código na subclasseMais cabeamento
Um eixo de variaçãoEixos combináveis
Fixo em compilaçãoTrocável em execução
Acoplado à implementação da baseAcoplado só à interface
Ganchos criam contrato implícitoInterface explícita

Modos de Falha

Base frágil. Mudança na base quebra subclasses não tocadas.

Template sobrescrito. A subclasse altera a sequência e a garantia se perde.

Ganchos demais. Contrato implícito ilegível.

Hierarquia profunda. Descobrir de onde vem um comportamento exige percorrer vários níveis.

Etapa que precisa de dado que a base não passa. A subclasse recorre a estado compartilhado, e o acoplamento se agrava.

Erros Comuns

Não tornar o template final.

Usar onde Strategy serve melhor. O erro mais comum em código de aplicação.

Acumular ganchos.

Compartilhar estado mutável entre base e subclasse. Torna a ordem de execução uma dependência oculta.

Onde ele aparece na prática

Frameworks de teste. O ciclo — preparar, executar, verificar, limpar — é um template; seus métodos preenchem as lacunas.

Servlets e controladores. A classe base trata o protocolo; você implementa o tratamento da requisição.

Classes abstratas de coleção. AbstractList implementa quase tudo a partir de duas operações que a subclasse fornece.

Etapas de processamento em lote. Frameworks de processamento definem o ciclo e você preenche leitura, processamento e escrita.

Os quatro são código de framework. É onde o padrão pertence: quando a base é uma biblioteca e a subclasse é o código do usuário, a inversão de controle é exatamente o que se quer. Em código de aplicação, onde os dois lados são seus, Strategy costuma vencer.

Exemplo Real

Um sistema de importação tinha ImportadorBase com sete etapas e onze subclasses, uma por formato de arquivo.

Funcionou por dois anos. O problema apareceu quando o destino passou a variar: o mesmo formato podia ir para o banco principal, para um data warehouse ou para uma fila. A hierarquia teria 33 classes.

A migração para composição foi parcial e deliberada. O esqueleto virou uma função que recebe um leitor e um escritor:

importar(leitor, escritor)
abrir · validar · transformar · gravar · fechar

Onze leitores, três escritores. A sequência continuou garantida — está na função, não numa base herdada.

O detalhe que vale reter: o padrão não estava errado enquanto havia um eixo. Ele deixou de servir quando apareceu o segundo, que é exatamente a limitação declarada em "quando não usar" — e a mesma que derrubou Factory Method num caso análogo.

Como converter para Strategy

A conversão é mecânica quando o padrão deixa de servir, e vale conhecer os passos.

Um. Identifique as operações abstratas — as lacunas que as subclasses preenchem. Cada conjunto que varia junto é uma estratégia.

Dois. Transforme cada conjunto numa interface. Se for uma operação só, uma função basta.

Três. Converta o método template em uma função ou classe que recebe as estratégias como parâmetros. A sequência permanece; o que muda é de onde vêm as etapas.

Quatro. Cada subclasse antiga vira uma combinação de estratégias, montada onde o objeto era instanciado.

antes: ImportadorCSV extends ImportadorBase
depois: importar(leitorCSV, escritorBanco)

Cinco. Os ganchos com implementação padrão viram parâmetros opcionais com valor padrão.

O passo que costuma travar é o quarto: se as subclasses compartilhavam estado com a base por campos protegidos, esse estado precisa virar parâmetro explícito. É trabalhoso e é justamente o acoplamento que a conversão elimina — o estado compartilhado era uma dependência oculta entre base e subclasse.

Conceitos Relacionados

Exercício Prático

Procure classes abstratas do seu sistema com um método público não sobrescrevível que chama métodos abstratos.

Para cada uma, conte os eixos de variação e os ganchos. Mais de um eixo, ou muitos ganchos, indica que composição serviria melhor.

Perguntas de Entrevista

  • Por que o método template deve ser final?
  • Qual a diferença entre gancho e operação abstrata?
  • Quando Strategy é preferível a Template Method?

Para Aprofundar

  • Gamma, Erich et al. Design Patterns. Addison-Wesley, 1994.
  • Bloch, Joshua. Effective Java. 3ª ed., 2018 — sobre projetar para herança.