Desafio Java
Sistema de relatórios com template method e hook
Enunciado
Crie uma classe abstrata Relatorio com o template method gerar() que executa: cabecalho(), corpo(), rodape() e, opcionalmente, anexo() (um hook). O hook anexo() tem implementação padrão vazia e pode ser sobrescrito. cabecalho() e rodape() são concretos. corpo() é abstrato. Implemente RelatorioPDF e RelatorioCSV, sendo que apenas RelatorioCSV sobrescreve anexo() para imprimir "Anexo: dados brutos". No main, gere os dois relatórios.
Requisitos
Relatoriodeve ser abstrata e tergerar()comofinal.corpo()deve ser abstrato e implementado nas subclasses.anexo()deve ser um hook concreto com corpo vazio.- Apenas
RelatorioCSVsobrescreveanexo(). - A saída deve mostrar a sequência completa para cada relatório.
Código inicial
abstract class Relatorio {
public final void gerar() {
// implemente a sequência
}
protected void cabecalho() {
System.out.println("Cabeçalho: Relatório");
}
protected abstract void corpo();
protected void rodape() {
System.out.println("Rodapé: Fim do relatório");
}
protected void anexo() {
// hook vazio
}
}
class RelatorioPDF extends Relatorio {
@Override
protected void corpo() {
// implemente
}
}
class RelatorioCSV extends Relatorio {
@Override
protected void corpo() {
// implemente
}
@Override
protected void anexo() {
// implemente
}
}
public class Main {
public static void main(String[] args) {
Relatorio pdf = new RelatorioPDF();
pdf.gerar();
System.out.println("---");
Relatorio csv = new RelatorioCSV();
csv.gerar();
}
}
Saída esperada
Cabeçalho: Relatório
Corpo: Conteúdo em PDF
Rodapé: Fim do relatório
---
Cabeçalho: Relatório
Corpo: Conteúdo em CSV
Rodapé: Fim do relatório
Anexo: dados brutos
Ver dica
No método gerar(), chame cabecalho(), corpo(), rodape() e depois anexo(). O hook anexo() já tem implementação vazia na classe base; apenas RelatorioCSV o sobrescreve.
Mostrar solução
abstract class Relatorio {
// Template method: define a ordem dos passos
public final void gerar() {
cabecalho();
corpo();
rodape();
anexo(); // hook opcional
}
protected void cabecalho() {
System.out.println("Cabeçalho: Relatório");
}
protected abstract void corpo();
protected void rodape() {
System.out.println("Rodapé: Fim do relatório");
}
// Hook: implementação padrão vazia
protected void anexo() {
}
}
class RelatorioPDF extends Relatorio {
@Override
protected void corpo() {
System.out.println("Corpo: Conteúdo em PDF");
}
}
class RelatorioCSV extends Relatorio {
@Override
protected void corpo() {
System.out.println("Corpo: Conteúdo em CSV");
}
@Override
protected void anexo() {
System.out.println("Anexo: dados brutos");
}
}
public class Main {
public static void main(String[] args) {
Relatorio pdf = new RelatorioPDF();
pdf.gerar();
System.out.println("---");
Relatorio csv = new RelatorioCSV();
csv.gerar();
}
}
Passo a passo
Relatorioé abstrata e definegerar()comofinalpara fixar a ordem dos passos.cabecalho()erodape()são concretos e compartilhados.corpo()é abstrato e obriga as subclasses a fornecerem o conteúdo específico.anexo()é um hook: método concreto com corpo vazio, que pode ser sobrescrito opcionalmente.RelatorioPDFimplementacorpo()e não mexe no hook.RelatorioCSVimplementacorpo()e sobrescreveanexo()para adicionar dados brutos.- No
main, chamamosgerar()para cada relatório, e a saída reflete as diferenças.
Por que funciona
O Template Method permite que a classe base controle o fluxo do algoritmo, enquanto as subclasses personalizam partes específicas. O hook anexo() é um ponto de extensão opcional: se não for sobrescrito, nada acontece. Isso é útil para adicionar comportamento sem quebrar o esqueleto.
Erros comuns
- Esquecer de chamar
anexo()no template method: o hook nunca seria executado. - Declarar
anexo()como abstrato: forçaria todas as subclasses a implementá-lo, perdendo a opcionalidade. - Não marcar
gerar()comofinal: subclasses poderiam alterar a ordem dos passos.
Outra forma de resolver
Poderia usar uma interface com métodos default para o hook, mas classes abstratas permitem melhor controle de visibilidade e estado compartilhado.
Saída esperada
Cabeçalho: Relatório
Corpo: Conteúdo em PDF
Rodapé: Fim do relatório
---
Cabeçalho: Relatório
Corpo: Conteúdo em CSV
Rodapé: Fim do relatório
Anexo: dados brutos