Padrão Template Method
Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy. Lição 99 de 104.
O padrão Template Method define o esqueleto de um algoritmo em uma classe base, permitindo que as subclasses substituam etapas específicas sem alterar a estrutura geral do algoritmo. Diferentemente de Strategy, que troca algoritmos inteiros, o Template Method mantém o algoritmo fixo e permite a personalização de etapas individuais.
A classe base implementa o método template (o algoritmo) e chama métodos abstratos ou virtuais que as subclasses devem fornecer:
#include <iostream>
class DataProcessor {
public:
// Método template - define o esqueleto do algoritmo
void process() {
loadData();
processData();
saveResults();
}
virtual ~DataProcessor() = default;
protected:
virtual void loadData() = 0; // Deve ser implementado
virtual void processData() = 0; // Deve ser implementado
// Hook - sobrescrita opcional com comportamento padrão
virtual void saveResults() {
std::cout << "Saving to default location\n";
}
};
class CSVProcessor : public DataProcessor {
protected:
void loadData() override {
std::cout << "Loading CSV file\n";
}
void processData() override {
std::cout << "Parsing CSV data\n";
}
};
class JSONProcessor : public DataProcessor {
protected:
void loadData() override {
std::cout << "Loading JSON file\n";
}
void processData() override {
std::cout << "Parsing JSON data\n";
}
void saveResults() override {
std::cout << "Saving to cloud storage\n";
}
};
int main() {
CSVProcessor csv;
csv.process(); // Usa o saveResults padrão
JSONProcessor json;
json.process(); // Usa o saveResults personalizado
}O método process() é o método template — ele define a sequência fixa de etapas. As subclasses implementam loadData() e processData() de maneira diferente, mas a ordem nunca muda. O método saveResults() é um “hook” — ele tem uma implementação padrão que as subclasses podem substituir opcionalmente.
Use o Template Method quando você tiver um algoritmo com etapas invariáveis, mas precisar de flexibilidade em operações específicas, ou quando quiser evitar a duplicação de código entre classes semelhantes.
Desafio
FácilVamos criar um sistema de Gerador de Relatórios usando o padrão Template Method. Você criará uma estrutura na qual diferentes tipos de relatórios (como relatórios de vendas e relatórios de inventário) seguem o mesmo processo de geração, mas cada tipo de relatório personaliza etapas específicas. Este é um cenário perfeito para o Template Method: o fluxo de trabalho geral permanece fixo, enquanto as etapas individuais variam.
Você organizará seu código em três arquivos:
ReportGenerator.h: Defina a classe base abstrata com o método template.Crie uma classe
ReportGeneratorque defina o esqueleto do algoritmo de geração de relatórios. Seu método templategenerateReport()deve executar estas etapas na ordem:gatherData(): virtual pura, deve ser implementada pelas subclassesformatReport(): virtual pura, deve ser implementada pelas subclassesaddHeader(): um hook com comportamento padrão que imprime--- Report ---printReport(): virtual pura, deve ser implementada pelas subclasses
O método
addHeader()atua como um hook que as subclasses podem opcionalmente sobrescrever para personalizar o cabeçalho.Reports.h: Implemente dois geradores de relatórios concretos.Crie uma classe
SalesReportque:gatherData()imprimeGathering sales data from databaseformatReport()imprimeFormatting sales figuresprintReport()imprimeSales Total: $[amount], em que amount é passado para o construtor
Crie uma classe
InventoryReportque:gatherData()imprimeScanning inventory recordsformatReport()imprimeOrganizing inventory by categoryaddHeader()sobrescreve o hook para imprimir=== Inventory Report ===printReport()imprimeItems in stock: [count], em que count é passado para o construtor
Ambas as classes devem aceitar seus respectivos valores (amount ou count) por meio de seus construtores.
main.cpp: Demonstre o padrão Template Method.Leia duas entradas:
- Valor das vendas (inteiro)
- Quantidade de itens no inventário (inteiro)
Crie um
SalesReportcom o valor das vendas e gere o relatório. Em seguida, crie umInventoryReportcom a quantidade de itens no inventário e gere o relatório. Imprima uma linha em branco entre os dois relatórios para facilitar a leitura.
Por exemplo, com as entradas 15000 e 250:
Gathering sales data from database
Formatting sales figures
--- Report ---
Sales Total: $15000
Scanning inventory records
Organizing inventory by category
=== Inventory Report ===
Items in stock: 250Com as entradas 8500 e 120:
Gathering sales data from database
Formatting sales figures
--- Report ---
Sales Total: $8500
Scanning inventory records
Organizing inventory by category
=== Inventory Report ===
Items in stock: 120Observe como ambos os relatórios seguem exatamente a mesma sequência de etapas definida em generateReport(), mas cada um implementa essas etapas de maneira diferente. O InventoryReport também demonstra a sobrescrita do método hook para personalizar o cabeçalho, enquanto o SalesReport usa o comportamento padrão. Este é o padrão Template Method em ação: a estrutura do algoritmo é fixada na classe base, mas os detalhes são flexíveis.
Experimente você mesmo
#include <iostream>
#include "Reports.h"
using namespace std;
int main() {
// Ler entradas
int salesAmount;
int inventoryCount;
cin >> salesAmount;
cin >> inventoryCount;
// TODO: Crie um SalesReport com salesAmount e o gere
// TODO: Imprima uma linha em branco entre os relatórios
// TODO: Create an InventoryReport with inventoryCount and generate it
return 0;
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos externosBuild e compilação em C++Arquivos de cabeçalho e arquivos-fonteNamespaces e escopoIntrodução à POO em C++Classes vs. objetosO ponteiro 'this'Métodos (funções membro)Atributos (membros de dados)Noções básicas de construtores e destruidoresRevisão - calculadora simples4Propriedades de Classe
Membros de Instância vs. EstáticosGetters e SettersFunções Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRevisão - Gerenciador de Contas Bancárias7Herança
Herança básicaNíveis de acesso da herançaOrdem de chamada de construtor e destrutorSobrescrita de métodosFunções virtuais e VTableHerança múltiplaHerança virtualRevisão - Hierarquia de funcionários10Visão geral da STL
Visão geral e filosofia da STLContêineres da STLIteradoresAlgoritmos da STLFunctors e expressões lambdaRecapitulação - Frequência de palavras13Padrões de Projeto — Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonFactory e Abstract FactoryPadrão BuilderPadrão ObserverPadrão Strategy2Gerenciamento de Memória
Memória Stack vs. HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Ponteiros Inteligentes em C++RAII em C++Revisão - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de acesso em C++Especificadores de acesso em profundidadeOcultação de informaçõesStruct vs ClasseClasses aninhadas e internasRecapitulação - Sistema de registros de alunos8Polimorfismo
Polimorfismo em compilação vs. execuçãoSobrecarga de funçõesFunções virtuais revisadasFunções virtuais purasClasses abstratasDesign de interfaces em C++Conversão dinâmica e RTTIRecapitulação — Calculadora de formas11Conceitos Avançados de OOP
Composição vs. HerançaMixins via CRTPIdioma PimplApagamento de TiposClasses Enum e Tipagem ForteTratamento de Exceções em OOPHierarquias de Exceções Personalizadas14Padrões de Projeto — Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositeRAII como Padrão3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentoListas de Inicialização do ConstrutorConstrutores DelegantesAprofundamento em DestrutoresRegra dos Três / Cinco / ZeroRevisão - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de FluxoSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçõesTemplates de ClassesEspecialização de TemplatesTemplates VariádicosNoções Básicas de SFINAE e Traits de TiposRecapitulação - Contêiner GenéricoPratique por conta própria: Compilador de C++ online