Menu
Coddy logo textTech

Template Method Pattern

Part of the Object Oriented Programming section of Coddy's C++ journey — lesson 99 of 104.

The Template Method pattern defines the skeleton of an algorithm in a base class, letting subclasses override specific steps without changing the algorithm's overall structure. Unlike Strategy, which swaps entire algorithms, Template Method keeps the algorithm fixed while allowing customization of individual steps.

The base class implements the template method (the algorithm) and calls abstract or virtual methods that subclasses must provide:

#include <iostream>

class DataProcessor {
public:
    // Template method - defines the algorithm skeleton
    void process() {
        loadData();
        processData();
        saveResults();
    }
    
    virtual ~DataProcessor() = default;
    
protected:
    virtual void loadData() = 0;      // Must be implemented
    virtual void processData() = 0;   // Must be implemented
    
    // Hook - optional override with default behavior
    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();  // Uses default saveResults
    
    JSONProcessor json;
    json.process(); // Uses custom saveResults
}

The process() method is the template method - it defines the fixed sequence of steps. Subclasses implement loadData() and processData() differently, but the order never changes. The saveResults() method is a "hook" - it has a default implementation that subclasses can optionally override.

Use Template Method when you have an algorithm with invariant steps but need flexibility in specific operations, or when you want to avoid code duplication across similar classes.

challenge icon

Challenge

Easy

Let's build a Report Generator system using the Template Method pattern. You'll create a framework where different types of reports (like sales reports and inventory reports) follow the same generation process, but each report type customizes specific steps. This is a perfect scenario for Template Method—the overall workflow stays fixed while individual steps vary.

You'll organize your code across three files:

  • ReportGenerator.h: Define the abstract base class with the template method.

    Create a ReportGenerator class that defines the skeleton of the report generation algorithm. Your template method generateReport() should execute these steps in order:

    1. gatherData() — pure virtual, must be implemented by subclasses
    2. formatReport() — pure virtual, must be implemented by subclasses
    3. addHeader() — a hook with default behavior that prints --- Report ---
    4. printReport() — pure virtual, must be implemented by subclasses

    The addHeader() method serves as a hook that subclasses can optionally override to customize the header.

  • Reports.h: Implement two concrete report generators.

    Create a SalesReport class that:

    • gatherData() prints Gathering sales data from database
    • formatReport() prints Formatting sales figures
    • printReport() prints Sales Total: $[amount] where amount is passed to the constructor

    Create an InventoryReport class that:

    • gatherData() prints Scanning inventory records
    • formatReport() prints Organizing inventory by category
    • addHeader() overrides the hook to print === Inventory Report ===
    • printReport() prints Items in stock: [count] where count is passed to the constructor

    Both classes should accept their respective values (amount or count) through their constructors.

  • main.cpp: Demonstrate the Template Method pattern.

    Read two inputs:

    1. Sales amount (integer)
    2. Inventory count (integer)

    Create a SalesReport with the sales amount and generate it. Then create an InventoryReport with the inventory count and generate it. Print a blank line between the two reports for readability.

For example, with inputs 15000 and 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

With inputs 8500 and 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

Notice how both reports follow the exact same sequence of steps defined in generateReport(), but each implements those steps differently. The InventoryReport also demonstrates overriding the hook method to customize the header, while SalesReport uses the default. This is the Template Method pattern in action—the algorithm structure is locked in the base class, but the details are flexible.

Cheat sheet

The Template Method pattern defines the skeleton of an algorithm in a base class, letting subclasses override specific steps without changing the algorithm's overall structure.

The base class implements the template method (the algorithm) and calls abstract or virtual methods that subclasses must provide:

#include <iostream>

class DataProcessor {
public:
    // Template method - defines the algorithm skeleton
    void process() {
        loadData();
        processData();
        saveResults();
    }
    
    virtual ~DataProcessor() = default;
    
protected:
    virtual void loadData() = 0;      // Must be implemented
    virtual void processData() = 0;   // Must be implemented
    
    // Hook - optional override with default behavior
    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";
    }
};

The template method defines the fixed sequence of steps. Subclasses implement abstract methods differently, but the order never changes. Hook methods have default implementations that subclasses can optionally override.

Use Template Method when you have an algorithm with invariant steps but need flexibility in specific operations, or when you want to avoid code duplication across similar classes.

Try it yourself

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

using namespace std;

int main() {
    // Read inputs
    int salesAmount;
    int inventoryCount;
    cin >> salesAmount;
    cin >> inventoryCount;
    
    // TODO: Create a SalesReport with salesAmount and generate it
    
    // TODO: Print a blank line between reports
    
    // TODO: Create an InventoryReport with inventoryCount and generate it
    
    return 0;
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming