Menu
Coddy logo textTech

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 subclasses sobrescrevam etapas específicas sem alterar a estrutura geral do algoritmo. Ao contrário do Strategy, que troca algoritmos inteiros, o Template Method mantém o algoritmo fixo enquanto permite a customizaçã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:
    // Template method - 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 forma diferente, mas a ordem nunca muda. O método saveResults() é um "hook" - ele possui uma implementação padrão que as subclasses podem opcionalmente sobrescrever.

Use o Template Method quando você tiver um algoritmo com passos invariantes, mas precisar de flexibilidade em operações específicas, ou quando quiser evitar a duplicação de código entre classes semelhantes.

challenge icon

Desafio

Fácil

Vamos construir um sistema de Gerador de Relatórios usando o padrão Template Method. Você criará uma estrutura onde diferentes tipos de relatórios (como relatórios de vendas e relatórios de estoque) 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: Define a classe base abstrata com o método template.

    Crie uma classe ReportGenerator que defina o esqueleto do algoritmo de geração de relatório. Seu método template generateReport() deve executar estas etapas em ordem:

    1. gatherData() — virtual pura, deve ser implementada pelas subclasses
    2. formatReport() — virtual pura, deve ser implementada pelas subclasses
    3. addHeader() — um hook com comportamento padrão que imprime --- Report ---
    4. printReport() — virtual pura, deve ser implementada pelas subclasses

    O método addHeader() serve como um hook que as subclasses podem opcionalmente sobrescrever para personalizar o cabeçalho.

  • Reports.h: Implementa dois geradores de relatórios concretos.

    Crie uma classe SalesReport que:

    • gatherData() imprime Gathering sales data from database
    • formatReport() imprime Formatting sales figures
    • printReport() imprime Sales Total: $[amount] onde amount é passado para o construtor

    Crie uma classe InventoryReport que:

    • gatherData() imprime Scanning inventory records
    • formatReport() imprime Organizing inventory by category
    • addHeader() sobrescreve o hook para imprimir === Inventory Report ===
    • printReport() imprime Items in stock: [count] onde count é passado para o construtor

    Ambas as classes devem aceitar seus respectivos valores (amount ou count) através de seus construtores.

  • main.cpp: Demonstra o padrão Template Method.

    Leia duas entradas:

    1. Valor de vendas (inteiro)
    2. Contagem de estoque (inteiro)

    Crie um SalesReport com o valor de vendas e gere-o. Em seguida, crie um InventoryReport com a contagem de estoque e gere-o. Imprima uma linha em branco entre os dois relatórios para legibilidade.

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: 250

Com 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: 120

Observe como ambos os relatórios seguem exatamente a mesma sequência de etapas definida em generateReport(), mas cada um implementa essas etapas de forma diferente. O InventoryReport também demonstra a sobrescrita do método hook para personalizar o cabeçalho, enquanto o SalesReport usa o padrão. Este é o padrão Template Method em ação — a estrutura do algoritmo está travada na classe base, mas os detalhes são flexíveis.

Folha de consulta

O padrão Template Method define o esqueleto de um algoritmo em uma classe base, permitindo que subclasses sobrescrevam etapas específicas sem alterar a estrutura geral do algoritmo.

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";
    }
};

O método template define a sequência fixa de etapas. As subclasses implementam métodos abstratos de forma diferente, mas a ordem nunca muda. Métodos hook têm implementações padrão que as subclasses podem opcionalmente sobrescrever.

Use o Template Method quando você tiver um algoritmo com etapas invariantes, mas precisar de flexibilidade em operações específicas, ou quando quiser evitar a duplicação de código entre classes semelhantes.

Experimente você mesmo

#include <iostream>
#include "Reports.h"

using namespace std;

int main() {
    // Ler entradas
    int salesAmount;
    int inventoryCount;
    cin >> salesAmount;
    cin >> inventoryCount;
    
    // TODO: Criar um SalesReport com salesAmount e gerá-lo
    
    // TODO: Imprimir uma linha em branco entre os relatórios
    
    // TODO: Criar um InventoryReport com inventoryCount e gerá-lo
    
    return 0;
}
quiz iconTeste seus conhecimentos

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