Template Pattern
The Template Method Pattern is a classic behavioral design pattern that establishes the skeleton of an algorithm in an abstract base class, deferring specific implementation steps to subclasses. This structural approach allows subclasses to redefine or extend certain steps of an algorithm without altering its overall control flow, effectively promoting code reuse and modular extensibility.
| Component | Responsibility |
|---|---|
| AbstractClass | Declares the template method defining the invariant algorithm sequence, along with abstract primitive operations or optional hooks to be implemented by subclasses. |
| ConcreteClass | Implements the primitive operations defined in the abstract class to fulfill specific business logic, and optionally overrides hook methods. |
| Hook | An optional method with a default (often empty) implementation in the abstract class, providing strategic extension points for subclasses. |
Structural Overview
templateMethod(): The core routine that orchestrates the workflow. It is typically marked asfinalto prevent subclasses from modifying the core algorithm sequence.primitiveOperationX(): Abstract steps that mandate custom implementations tailored to specific scenarios.hook(): An optional extension mechanism enabling customized conditional behavior.
When to Use
- Invariable Workflows with Variable Details: When an application follows a strict, predictable sequence of steps, but individual steps require context-specific implementations.
- Eliminating Code Duplication: When common behavior across multiple classes needs to be centralized into a parent class to adhere to the DRY (Don't Repeat Yourself) principle.
- Enforcing Architectural Boundaries: When you need to control subclass behavior by mandating a rigid execution order, preventing unauthorized modifications to the workflow.
Pros and Cons Analysis
Advantages
- High Code Reuse: Common logic resides in a single location within the base class, while subclasses focus strictly on differentiating details.
- Simplified Maintenance: Modifying the high-level workflow requires updating only the parent class.
- Flexible Extension Points: Hooks and primitive operations offer clean customization pathways without breaking the core structure.
Disadvantages
- Increased Class Count: Each distinct workflow requires a dedicated abstract class and corresponding subclasses, potentially compounding system complexity.
- Tight Coupling: Subclasses are inherently bound to the structural contract dictated by the parent class, which can limit architectural freedom if the base class is poorly designed.
Java Implementation
public abstract class AbstractReport {
public final void generateReport() {
readData();
processData();
formatReport();
if (hook()) {
exportReport();
}
}
protected abstract void readData();
protected abstract void processData();
protected abstract void formatReport();
protected boolean hook() {
return false;
}
private void exportReport() {
System.out.println("Exporting report to file...");
}
}
public class PDFReport extends AbstractReport {
@Override
protected void readData() {
System.out.println("Reading data from database...");
}
@Override
protected void processData() {
System.out.println("Aggregating and computing statistics...");
}
@Override
protected void formatReport() {
System.out.println("Formatting document into PDF layout...");
}
@Override
protected boolean hook() {
return true;
}
}
Python Implementation
from abc import ABC, abstractmethod
class AbstractProcessor(ABC):
def process(self):
self.read()
self.transform()
self.save()
if self.hook():
self.notify()
@abstractmethod
def read(self):
pass
@abstractmethod
def transform(self):
pass
@abstractmethod
def save(self):
pass
def hook(self):
return False
def notify(self):
print("Process completed. Sending notification...")
class CSVProcessor(AbstractProcessor):
def read(self):
print("Reading source CSV file...")
def transform(self):
print("Cleaning and transforming rows...")
def save(self):
print("Persisting data to JSON store...")
def hook(self):
return True
Best Practices
- Protect the Template Method
Always seal or designate the main template method as non-overridable (finalin Java or C++) to protect the integrity of the algorithm workflow. - Design Meaningful Hooks
Provide sensible default behaviors for hooks so that subclasses only override them when custom behavior is explicitly required. - Guard Against Over-Abstraction
Do not introduce template hierarchies prematurely if only a single implementation exists or if the variations are trivial. - Adhere to the Single Responsibility Principle
Keep the abstract class focused purely on orchestrating workflow steps, leaving domain-specific execution details entirely to the subclasses.
Summary
The Template Method Pattern strikes an optimal balance between code reuse and behavioral governance by codifying algorithm frameworks in parent classes while delegating concrete steps to subclasses. Ideal for standardized pipelines such as data processing, report generation, and lifecycle management, mastering this pattern empowers developers to write cleaner, more resilient, and easily extensible architectures.