Behavioral Patterns
Template Method
Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
The Template Method Pattern is a behavioral design pattern that defines the programmatic skeleton of an algorithm in a base class, delegating specific execution steps to subclasses. By locking the overarching algorithm flow within a final method while exposing abstract hook methods for variant steps, it maximizes code reuse and enforces consistent step ordering.
1. Learning Objectives
- Identify duplicate procedural skeletons across multiple classes and extract them into template patterns.
- Differentiate between the roles of abstract methods and optional Hook methods.
- Apply the Hollywood Principle ("Don't call us, we'll call you") to manage parent-child call structures.
- Analyze vtable (virtual method table) dynamic lookup costs for virtual hook dispatches.
- Implement the Non-Virtual Interface (NVI) variant of the Template Method pattern in C++.
2. Problem & Naive Solution
Suppose you are building a data ingestion engine. The system imports records from various raw source formats: CSV files and JSON files. For both formats, the parsing steps follow a strict sequence:
- Open the file stream socket.
- Extract the raw records into an internal model.
- Perform validation checks (e.g. check for null values).
- Close the file stream socket to prevent memory leaks.
The Naive Solution
A developer might implement independent classes for each parser type, copy-pasting the lifecycle logic:
This copy-paste approach exposes several design flaws:
- Code Duplication: The socket opening, error validation logs, and closing operations are duplicated across all parser classes.
- Brittle Stream Closures: If a subclass developer forgets to close the file stream inside a custom try-catch block, the system leaks file descriptors, risking thread hangs.
- Inconsistent Steps: Different developers might skip steps (e.g. bypassing validation checks), causing data corruption downstream.
3. Issues
Without a unified base algorithm template, you cannot guarantee consistent execution steps. Adding validation policies or diagnostic logs requires modifying all parser classes individually, violating DRY (Don't Repeat Yourself) guidelines.
4. Pattern Introduction & UML
The Template Method Pattern addresses this by defining the algorithm skeleton inside an abstract base class (DataParser). The main execution method is declared final to prevent subclasses from altering the step sequence. The base class implements standard steps (like opening and closing files) and exposes abstract methods (like extractData()) for subclasses to implement custom parsing logic.
UML: Data Parsing Pipeline
5. Participants
- Abstract Class (
DataParser): Declares thefinaltemplate method defining the algorithm steps, along with abstract hooks for sub-steps. - Concrete Class (
CsvParser,JsonParser): Overrides the abstract steps to implement format-specific parsing algorithms.
6. Theory (The Hollywood Principle & Hooks)
The Template Method pattern relies on key architectural principles:
- Hollywood Principle: "Don't call us, we'll call you." Concrete subclasses do not call parent methods directly. Instead, the parent class invokes the subclass implementations at the appropriate step in the algorithm flow.
- Abstract Methods vs. Hooks: - *Abstract Methods*: Must be overridden by subclasses to implement mandatory steps of the algorithm. - *Hooks*: Concrete methods in the base class with default implementations. Subclasses can optionally override them to alter the template flow (e.g., toggling validation checks via a boolean hook).
7. Syntax Explanation
Syntax structures for templates in different languages:
- Java: Uses
finalkeywords on the template method (public final void parse()) to prevent subclasses from overriding and breaking the step sequence. - Python: Lacks final methods at compiler level, but relies on properties or naming conventions (e.g., prefixing with underscores) to signal read-only status.
- C++: Implements the Non-Virtual Interface (NVI) pattern. The template method is public and non-virtual, while the customizable steps are declared private virtual virtual helper functions, enforcing encapsulation.
8. Step-by-Step Implementation
- Step 1: Create the abstract base class and declare the template method as final/non-virtual.
- Step 2: Write the step-by-step algorithm flow inside the template method.
- Step 3: Declare the shared steps as helper methods in the base class.
- Step 4: Declare variant steps as abstract or virtual methods, and write default behaviors for optional hook methods.
- Step 5: Create subclass implementations overriding the abstract/hook methods to customize execution steps.
9. Complete Code (Mini Project)
10. Code Walkthrough
Let's review the framework delegation:
- Algorithm Guard: Declaring
parseDataFile()as final in Java and non-virtual in C++ prevents subclasses from altering the step sequence, ensuring that connection closure and validation always execute in order. - Hollywood Call Structure: The client invokes
parseDataFile(). The base class executes shared logic and callsextractData(), delegating control to the subclass implementation. - NVI Pattern Encapsulation: In the C++ example, the public template method is non-virtual, while the customizable steps are declared private virtual helper functions. This ensures subclasses cannot access or invoke the sub-steps directly.
11. Execution Flow
- Client Invocation: Client calls
parseDataFile()on the parser subclass. - Shared Init: The base class opens the file stream resource.
- Subclass Extraction: The base class calls
extractData(), executing the subclass implementation. - Hook Check: The base class checks
customerWantsValidation(). If true, it runs validation. - Shared Cleanup: The base class closes the file stream.
12. Internal Working (vtable Dispatch Optimizations)
Virtual method invocations introduce a minor compile-time and runtime cost:
- vtable Lookup: Calling virtual methods (like
extractData()) requires looking up the method address in the class's Virtual Method Table (vtable) at runtime, adding a slight performance overhead compared to direct static method binding. - NVI Performance Benefits: The Non-Virtual Interface (NVI) pattern ensures that only variant steps incur virtual dispatch costs, while shared helper methods use faster direct static method binding.
13. Complexity Analysis
- Time Complexity: $O(1)$ constant time overhead to resolve the virtual method dispatch.
- Space Complexity: $O(1)$ constant memory overhead to hold base class reference pointers.
14. Best Practices
- Keep the Template Method Final: Always use the
finalkeyword (Java) or declare the method as non-virtual (C++) to prevent subclasses from overriding and altering the core algorithm skeleton. - Minimize Abstract Steps: Limit the number of abstract methods subclasses must implement to reduce developer integration overhead.
15. Common Mistakes
- Omitting Final Access modifiers: Allowing subclasses to override the template method, compromising the integrity of the algorithm skeleton.
- Violating Liskov Substitution: Subclass implementations overriding virtual methods in a way that breaks base class invariants or expectations.
16. Framework Usage
- Spring's JdbcTemplate: Spring uses Template Method to manage database connection lifecycles, statement preparation, and transaction scopes, letting developers focus on writing SQL.
- Java Servlets: The servlet container invokes the base class
service()template method, which automatically routes requests to subclass implementations likedoGet()ordoPost().
17. Interview Discussion
Answer: - Template Method: Extends behavior using inheritance. Subclasses override specific steps of an algorithm, but the overall structure is fixed at compile-time. - Strategy: Extends behavior using composition. The client injects different strategy objects at runtime to replace the entire algorithm.
Answer: The principle ("Don't call us, we'll call you") means that base classes control the execution flow and invoke subclass methods when needed, preventing subclasses from directly invoking parent logic.
Answer: NVI makes the public template method non-virtual to guarantee execution order, while declaring customizable steps as private/protected virtual helper methods. This separates the public API from customization points.
18. Practice Exercises
- Easy: Write a Python program simulating an order processing pipeline with steps: validation, payment, and packaging.
- Medium: Design a
GameLoadertemplate with steps for downloading assets, checking updates, and launching the game. - Hard: Build a microservice code build compiler pipeline supporting steps: compilation, unit testing, static lint analysis, and cloud deployment, using hooks to skip linting in debug mode.
19. Challenge Problem
Design an Enterprise Web Crawler Engine. The crawler operates in a loop: fetches raw page source, parses page URLs, extracts page content, and indexes indices. Different indexers parse formats uniquely (e.g. HTML, PDF). If indexing fails, the crawler must log transaction errors and update site tables. Write this crawler engine in Java, Python, or C++ and verify crawl executions across multiple format types.
20. Summary & Cheat Sheet
- Template Method defines algorithm skeletons in a base class, delegating steps to subclasses.
- Always use
final(Java) or non-virtual (C++) modifiers on template methods to protect the algorithm flow. - Use hooks to let subclasses optionally override or toggle parts of the execution flow.
- Subclasses are managed by the parent class, adhering to the Hollywood Principle.
21. Quiz
1. What is the primary purpose of the Template Method design pattern?
A) To adapt incompatible interfaces
B) To define the skeleton of an algorithm in a base class, letting subclasses override specific steps (Correct)
C) To swap entire algorithms at runtime using composition
2. Which modifier keyword in Java prevents subclasses from overriding the template method?
A) static
B) final (Correct)
C) synchronized
3. What is the Hollywood Principle?
A) "Only override public methods"
B) "Don't call us, we'll call you" - parent classes invoke subclass methods, not vice versa (Correct)
C) "Enforce compile-time safety check on all classes"
4. How does a Hook differ from an Abstract method in the base class?
A) Hooks cannot be overridden
B) Abstract methods require implementation; Hooks provide default empty implementations that subclasses can optionally override (Correct)
C) Hooks run on background thread lines
5. Which Spring framework database utility implements the Template Method pattern?
A) JdbcTemplate (Correct)
B) RestController
C) SpringApplication
6. What is a key design risk if you do not declare the template method as final?
A) Stack Overflow errors
B) Subclasses can override the template method and alter the algorithm's step sequence (Correct)
C) Heap memory leaks
7. How does Template Method differ from Strategy?
A) Template Method uses composition; Strategy uses inheritance
B) Template Method uses inheritance to vary parts of an algorithm; Strategy uses composition to replace the entire algorithm at runtime (Correct)
C) Template Method runs faster on Linux
8. What is the Non-Virtual Interface (NVI) pattern in C++?
A) Making all methods virtual inside helper modules
B) Declaring public methods as non-virtual, while making customizable steps virtual (Correct)
C) Avoiding pointers inside class structures
9. In C++, why are abstract steps declared virtual but protected or private in NVI?
A) To save CPU registry calls
B) To hide customization points from clients, ensuring they only call the public template API (Correct)
C) To enforce thread synchronization
10. Can you use Template Method to guarantee resources are closed?
A) Yes, by enclosing resource cleanup inside a finally block at the end of the template method (Correct)
B) No, resource closure must be managed by the client
C) Only when using database connection pools
22. Next Lesson Preview
In the next lesson, we will explore the Chain of Responsibility Pattern. We will learn how to pass requests along a chain of handlers, letting each handler decide whether to process the request or pass it to the next link!
Related Topics
- StrategyDefine a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients.
- IteratorAccess elements of an aggregate object sequentially without exposing its underlying representation (list, stack, tree, graph).
- ObserverDefine a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.