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
EasyLet'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
ReportGeneratorclass that defines the skeleton of the report generation algorithm. Your template methodgenerateReport()should execute these steps in order:gatherData()— pure virtual, must be implemented by subclassesformatReport()— pure virtual, must be implemented by subclassesaddHeader()— a hook with default behavior that prints--- Report ---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
SalesReportclass that:gatherData()printsGathering sales data from databaseformatReport()printsFormatting sales figuresprintReport()printsSales Total: $[amount]where amount is passed to the constructor
Create an
InventoryReportclass that:gatherData()printsScanning inventory recordsformatReport()printsOrganizing inventory by categoryaddHeader()overrides the hook to print=== Inventory Report ===printReport()printsItems 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:
- Sales amount (integer)
- Inventory count (integer)
Create a
SalesReportwith the sales amount and generate it. Then create anInventoryReportwith 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: 250With 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: 120Notice 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;
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesC++ Build & CompilationHeader Files & Source FilesNamespaces & ScopeIntroduction to OOP in C++Classes vs ObjectsThe 'this' PointerMethods (Member Functions)Attributes (Data Members)Ctors & Dtors BasicsRecap - Simple Calculator4Class Properties
Instance vs Static MembersGetters and SettersConst Member FunctionsMutable KeywordStatic Methods and VariablesFriend Functions & ClassesRecap - Bank Account Manager7Inheritance
Basic InheritanceInheritance Access LevelsCtor & Dtor Call OrderMethod OverridingVirtual Functions & VTableMultiple InheritanceVirtual InheritanceRecap - Employee Hierarchy2Memory Management
Stack vs Heap MemoryPointers and ReferencesDynamic Memory (new/delete)Smart Pointers in C++RAII in C++Recap - Dynamic Array Manager5Encapsulation
Access Specifiers in C++Access Specifiers In DepthInformation HidingStruct vs ClassNested & Inner ClassesRecap - Student Records System8Polymorphism
Compile vs Runtime PolymorphFunction OverloadingVirtual Functions RevisitedPure Virtual FunctionsAbstract ClassesInterface Design in C++Dynamic Casting & RTTIRecap - Shape Calculator11Advanced OOP Concepts
Composition vs InheritanceMixins via CRTPPimpl IdiomType ErasureEnum Classes & Strong TypingException Handling in OOPCustom Exception Hierarchies14Design Patterns Part 2
Command PatternAdapter PatternDecorator PatternTemplate Method PatternState PatternComposite PatternRAII as a Pattern3Constructors & Destructors
Default ConstructorParameterized ConstructorCopy ConstructorMove ConstructorConstructor Init ListsDelegating ConstructorsDestructor Deep DiveRule of Three / Five / ZeroRecap - String Class6Operator Overloading
Intro to Operator OverloadArithmetic Operator OverloadComparison Operator OverloadStream OperatorsAssignment Operator Overload[] and () Operator OverloadType Conversion OperatorsRecap - Matrix Class9Templates
Function TemplatesClass TemplatesTemplate SpecializationVariadic TemplatesSFINAE & Type Traits BasicsRecap - Generic Container