Behavioral design patterns are about how objects work together and who does which job. They keep complex logic simple and keep objects loosely coupled (each object depends on others as little as possible).
Imagine you are baking a cake from a recipe. The recipe lists the steps in a fixed order: preheat the oven, mix the ingredients, bake. The details can change, such as the flavor. The Template Method Pattern works the same way. One class fixes the order of the steps, and subclasses fill in the steps that differ.
1. What is the Template Method Pattern?
The Template Method Pattern is a behavioral design pattern that gives a job a fixed outline. A superclass (the parent class) holds the outline: the steps and their order. The steps that differ are left to subclasses (the child classes). The order never changes.
Formal Definition
The Template Method Pattern is a behavioral design pattern that gives an algorithm (a set of steps) a fixed blueprint. Subclasses can override (replace) some steps, but the overall structure stays the same. The parts that never change are protected, and the parts that vary can be customized.
Real-Life Analogy
The process of baking a cake (preheat oven, mix ingredients, bake, cool) is fixed. The ingredients or flavor may vary (chocolate, vanilla, etc.).
The Template Method Pattern is like the recipe. It fixes the steps, and each cake type fills in its own ingredients.
2. Four Structural Components
The pattern splits the job into four kinds of methods:
- Template Method (
finalmethod in Base Class): This method is the outline of the algorithm. It calls the steps in order. It isfinal, so subclasses cannot override it, and the order stays the same. - Primitive Operations (
abstractmethods): These are the steps that differ. An abstract method has no body, so every subclass must write its own. - Concrete Operations (
finalorprivateconcrete methods): These are the steps that are the same for everyone. They are written once in the base class and shared by all subclasses. - Hooks (
protectedoptional methods with default behavior): A hook is a step with a default body in the base class. A subclass may override it to change the behavior, but it does not have to.
3. Understanding the Problem: Parallel Pipeline Redundancy
Email and SMS both follow the same steps to send a message. If each channel is written as its own separate class, the same code gets copied into every class.
Issues in the Naive Code
- Code Duplication: Both
EmailNotificationandSMSNotificationcontain almost the same code for rate limit checking (blocking too many sends), message formatting, logging, and analytics. This breaks the DRY (Don't Repeat Yourself) principle and makes the code harder to maintain. - Hardcoded Behavior: The steps for sending are written straight inside each
send()method. To add a new type (e.g., Push Notification), you would copy the whole method again. - Lack of Extensibility: To change the rate limit check, logging, or analytics, you must edit every notification class. It is easy to miss one and end up with inconsistent behavior.
- Maintenance Overhead: Each new notification type adds another class with similar code, so the system gets harder to manage as it grows.
4. Class Diagram & Structural Layout
The Template Method Pattern uses inheritance to move the shared steps into a superclass. The superclass controls the order of the steps. The subclasses fill in only the steps that differ.
In the diagram, + means public, - means private and # means protected. The * marks an abstract method. EmailNotification writes only the two abstract methods. SMSNotification also overrides the hook postSendAnalytics.
5. How the Template Method Pattern Resolves the Issues
| Issue | Solution with Template Method Pattern |
|---|---|
| Code Duplication | The shared steps (rate limit checks, recipient validation, logging, etc.) now live in the base class, so they are written once. |
| Hardcoded Behavior | Each subclass handles its own channel (email or SMS), so changing one does not touch the other. |
| Lack of Extensibility | To add a new type (e.g., PushNotification), subclass NotificationSender and write the two abstract methods. |
| Maintenance Overhead | Shared logic is in one place, so a change to rate limit checks or logging means editing only the base class. |
6. Trade-Off Analysis
Pros
- Promotes Code Reusability: Subclasses share the common steps, so they follow the same algorithm without copied code.
- Supports OCP (Open/Closed Principle): You can add new behavior by writing a new subclass, without editing the base class.
- Enforces a Consistent Flow: The steps always run in the same order, so every subclass behaves in a predictable way.
- Allows Optional Customization via Hooks: A subclass can change a step through a hook without changing the base structure.
Cons
- Inheritance-Based Constraints: It relies on inheritance, so each subclass is tied closely to its base class and is less flexible.
- Fragile Base Class Risks: A change to the template in the base class can affect every subclass, so one feature is hard to change on its own.
- Rigid Algorithm Layouts: If the core steps differ a lot between use cases, the pattern stops working well. The Strategy Pattern is a better choice then.
- Subclass Proliferation: If many steps need customizing, you can end up with too many subclasses, which is hard to maintain.
7. When to Use the Template Method Pattern
- Algorithmic Uniformity: Several classes follow the same steps in the same order and differ in only a few details.
- Centralization of Boilerplate: You want to remove copied code (boilerplate, such as logging or checks) shared by parallel classes.
- Strict Sequential Governance: The steps must always run in one fixed order that no subclass can change.
- Framework Design: You are building a framework (a ready-made structure that other developers build on) and want users to customize only safe steps through protected hooks.
8. Real-World Implementations
- TUF+ Payment Flow: In TUF+, Indian and International payments follow the same sequence: validate the payment method, process the payment, update the account. The steps stay the same, but the details differ by subclass, such as validating a UPI ID for Indian payments or a credit card for international ones.
- Game Engines: Game engines like Unity or Unreal Engine use the Template Method Pattern in their game loop and rendering. Every frame runs the same steps (input handling, physics update, rendering). Each game customizes specific actions, such as rendering techniques or AI decisions, through subclassing.
- Web Frameworks: Frameworks like Spring or Django use the Template Method Pattern for request lifecycles. They fix the pipeline for handling an HTTP request (URL mapping, request parsing, filter chains, formatting). Developers override specific hooks like validation or template engine rendering.