Template Method Pattern
The Template Method Pattern is a behavioral design pattern that defines the skeleton of an algorithm in a base method, allowing certain steps to be implemented or customized by subclasses. This approach promotes code reuse, enforces a consistent process, and enables flexibility by letting subclasses override specific steps without altering the overall algorithm structure.
Real-World Analogy
Think of making tea or coffee. The general process is the same: boil water, brew the beverage, pour into a cup, and optionally add condiments. The steps are consistent, but the implementation of "brew beverage" differs.
Pattern Structure
classDiagram
class AbstractClass {
+TemplateMethod()
+BaseOperation1()
+BaseOperation2()
#RequiredOperation1()
#RequiredOperation2()
+Hook()
}
class ConcreteClass {
+RequiredOperation1()
+RequiredOperation2()
}
AbstractClass <|-- ConcreteClass
💻 Code Example
The following example demonstrates the Template Method pattern using a Beverage preparation scenario.
abstract class CaffeineBeverage {
public void PrepareRecipe() {
BoilWater();
Brew();
PourInCup();
AddCondiments();
}
void BoilWater() => Console.WriteLine("Boiling water");
void PourInCup() => Console.WriteLine("Pouring into cup");
public abstract void Brew();
public abstract void AddCondiments();
}
class Tea : CaffeineBeverage {
public override void Brew() => Console.WriteLine("Steeping the tea");
public override void AddCondiments() => Console.WriteLine("Adding lemon");
}
from abc import ABC, abstractmethod
class CaffeineBeverage(ABC):
def prepare_recipe(self):
self.boil_water()
self.brew()
self.pour_in_cup()
self.add_condiments()
def boil_water(self):
print("Boiling water")
def pour_in_cup(self):
print("Pouring into cup")
@abstractmethod
def brew(self): pass
@abstractmethod
def add_condiments(self): pass
class Tea(CaffeineBeverage):
def brew(self):
print("Steeping the tea")
def add_condiments(self):
print("Adding lemon")
Key Points
Component | Description |
---|---|
Template Method | Defines the steps of the algorithm |
Concrete Class | Implements abstract methods for specific steps |
Hook (optional) | Provides a default method which can be overridden |
When to Use
-
When multiple classes share the same algorithm structure.
Example:// Base class defines the template abstract class ReportGenerator { public void Generate() { FetchData(); FormatData(); PrintReport(); } protected abstract void FetchData(); protected abstract void FormatData(); protected virtual void PrintReport() => Console.WriteLine("Printing report..."); } // Subclass customizes steps class SalesReport : ReportGenerator { protected override void FetchData() => Console.WriteLine("Fetching sales data"); protected override void FormatData() => Console.WriteLine("Formatting sales data"); }
-
To prevent code duplication by reusing base logic.
Example:class DataProcessor(ABC): def process(self): self.load() self.transform() self.save() @abstractmethod def load(self): pass @abstractmethod def transform(self): pass def save(self): print("Saving data") class CsvProcessor(DataProcessor): def load(self): print("Loading CSV") def transform(self): print("Transforming CSV")
-
To enforce an invariant algorithm structure across implementations.
Example:abstract class Game { public void Play() { Start(); while (!IsOver()) { TakeTurn(); } End(); } protected abstract void Start(); protected abstract bool IsOver(); protected abstract void TakeTurn(); protected abstract void End(); }
Advantages and Disadvantages
Pros | Cons |
---|---|
Code reuse via base algorithm | Can lead to tight coupling with base class |
Improves consistency | Inflexible structure if too rigid |
🧠 Quiz
🔚 Conclusion
The Template Method Pattern is a powerful tool for ensuring consistency in algorithms while enabling flexibility in specific steps. By clearly defining the skeleton in a base class, and deferring step details to subclasses, it encourages reuse and clean structure in your codebase.