Skip to main content
Create your own
Lesson illustration

Implementing the Template Method Pattern

Hello! Welcome to your next lesson on behavioral design patterns.

In our previous lesson, we explored the State pattern, which is perfect for objects that behave differently depending on their internal state, like a vending machine or an ATM. We saw how it encapsulates state-specific logic into separate classes, cleaning up complex conditional code.

Today, we'll focus on a different kind of behavioral control by tackling the learning outcome: Apply the Template Method pattern to define an algorithm's skeleton in a base class.

This pattern addresses a common problem in software development: you have several algorithms that share the same high-level structure but differ in their specific implementation details. The Template Method pattern provides an elegant, inheritance-based solution to this, promoting code reuse and enforcing consistency.

The Core Idea: An Algorithm's Blueprint

Imagine you're developing a feature to export data in various formats like CSV, PDF, and Excel. The overall process is the same for all formats:

  1. Gather the data.
  2. Open an output file.
  3. Write the file header (format-specific).
  4. Write the data rows (format-specific).
  5. Write an optional footer.
  6. Close the file.

Notice that steps 1, 2, 5, and 6 are identical, while steps 3 and 4 are unique to each format. A naive approach would be to copy-paste the common logic into each exporter class (CsvExporter, PdfExporter, etc.). This leads to code duplication and maintenance headaches.

The Template Method pattern solves this by creating a "template" for the algorithm.

Template Method Pattern – Design Patterns (ep 13)

To build an intuition for this, let's watch the first part of Christopher Okhravi's video on the Template Method pattern. He uses excellent analogies, like a poster template, to explain the fundamental concept of having a fixed structure with 'slots' that need to be filled in.

Watch from the beginning to 07:05. Focus on the distinction he makes between the parts of a process that don't vary (the skeleton) and the parts that do (the details).

The key takeaway is that the Template Method pattern separates the invariant parts of an algorithm from the variant parts. The invariant parts form the "skeleton" defined in a base class, while the variant parts are implemented by subclasses.

Structure of the Template Method Pattern

The pattern is formally defined by a few key components. Let's explore them.

Template Method Design Pattern

The article 'Template Method Design Pattern' from AlgoMaster provides a concise breakdown of the pattern's structure and a great real-world analogy.

Read section '2. What is the Template Method Pattern'. Pay close attention to the descriptions of the AbstractClass and Concrete Classes, and the distinction between abstract methods and hook methods.

To summarize the structure:

  • Abstract Class: This class defines the algorithm's structure. It contains:
    • The templateMethod(): A method that defines the algorithm's skeleton. It calls the other steps in a specific order. In Java, this method is often declared as final to prevent subclasses from changing the sequence of steps.
    • Abstract Methods: These represent the required steps that vary. Subclasses must provide an implementation for them.
    • Hook Methods: These are optional steps. They are concrete methods in the base class with a default (often empty) implementation. Subclasses may override them to "hook into" the algorithm at specific points and provide custom behavior.

Here is a UML class diagram that illustrates the pattern using the data export example.

UML Diagram for Template Method Pattern: Tabular Report Example
This diagram shows an abstract `TabularReport` class defining the template method. The concrete `Excel` and `Csv` classes inherit from it and implement the format-specific steps, while reusing the common logic from the base class.

Implementation in Java: The Report Exporter

Let's see how to refactor the report exporter problem from a naive, repetitive implementation to a clean one using the Template Method pattern. Since you work with Java and Spring Boot, you'll appreciate how this pattern cleans up service layer logic where you often have similar workflows.

Template Method Design Pattern

Let's return to the AlgoMaster article. It provides a full, step-by-step Java implementation that refactors the initial problematic design.

First, quickly review section '1. The Problem: Exporting Reports' to understand the 'before' state with its code duplication. Then, read section '3. Implementing Template Method' carefully to see the 'after' state. Note how the AbstractReportExporter class centralizes the common logic in the exportReport() method.

The refactored code demonstrates the pattern's benefits perfectly:

  • DRY (Don't Repeat Yourself): The common logic for preparing data and handling files is in one place.
  • Consistency: The final exportReport() method guarantees that every exporter follows the exact same sequence of steps.
  • Extensibility: Adding an ExcelExporter is now trivial. You just create a new class, extend AbstractReportExporter, and implement the two required abstract methods. This follows the Open/Closed Principle.
Test your understanding!

Imagine you are building a data processing pipeline in a Spring Boot application. The pipeline must:

  1. Read data from a source.
  2. Parse the data.
  3. Validate the data against business rules.
  4. Transform the data.
  5. Save the data to a destination.

You need to support different file types (e.g., CSV and JSON). For both file types, the validation logic (step 3) and transformation logic (step 4) are identical. However, reading/parsing (steps 1-2) and saving (step 5) are different.

How would you structure this using the Template Method pattern? What would be the template method, the abstract methods, and the concrete methods in the base class?

Show answer

You would create an abstract base class, say DataProcessor.

  • Template Method: A final method processData() that calls the steps in order: readAndParse(), validate(), transform(), save().
  • Abstract Methods: readAndParse() and save() would be abstract, as they are specific to each file type.
  • Concrete Methods: validate() and transform() would be regular (non-abstract) methods implemented directly in the DataProcessor base class, as their logic is shared.
  • Concrete Classes: You would then create CsvDataProcessor and JsonDataProcessor, both extending DataProcessor and providing concrete implementations for readAndParse() and save().

Template Method vs. Strategy Pattern

The Template Method pattern relies on inheritance. A subclass is a specific version of the base class algorithm.

The Strategy pattern, which we discussed two lessons ago, relies on composition. A context has a strategy and can change it at runtime.

This distinction is critical.

Template Method Pattern – Design Patterns (ep 13)

Christopher Okhravi's video has a great section comparing the two patterns and discussing the classic 'composition over inheritance' principle.

Watch the segment from 07:05 to 15:48. Focus on how Template Method uses inheritance to vary steps within a fixed algorithm, while Strategy uses composition to swap out entire algorithms.

Here's a quick summary:

Aspect Template Method Strategy
Mechanism Inheritance Composition
Granularity Varies parts of an algorithm. Varies an entire algorithm.
Flexibility Less flexible. The algorithm's structure is fixed at compile time. More flexible. The strategy can be changed at runtime.
When to use When the overall algorithm is fixed and you only need to change specific steps. When you have multiple ways of doing a task and want the client to choose one.

The Hollywood Principle & Real-World Usage

The Template Method pattern embodies a concept called the "Hollywood Principle": Don't call us, we'll call you.

The high-level base class "calls" the low-level subclass methods to perform specific steps, but the subclasses don't call up to the base class. This is a form of Inversion of Control (IoC), a principle that is at the very heart of the Spring Framework you use daily. Frameworks often define skeletons for operations (like handling a web request or a transaction), and your application code provides the specific details by "filling in the blanks."

This pattern is not just theoretical; it's used extensively in the Java core libraries.

Implementing the Template Method Pattern in Java

The Baeldung article 'Implementing the Template Method Pattern in Java' provides a great example of this pattern's use within the JDK itself.

Read section '4. Template Methods in Java Core Libraries'. Seeing how java.util.AbstractList uses this pattern for its addAll() method will solidify your understanding of its practical utility.

The AbstractList's addAll method provides the looping logic, but it defers the actual work of adding each element to the add method, which must be implemented by concrete subclasses like ArrayList or LinkedList.

Conclusion

You have now learned how the Template Method pattern provides a straightforward way to structure algorithms that share a common sequence of steps. It's a fundamental pattern that relies on inheritance to achieve code reuse and enforce consistency.

Key Takeaways:

  • Purpose: To define the skeleton of an algorithm in a base class, deferring some steps to subclasses.
  • Structure: Comprises a final template method, abstract methods for required steps, and optional hook methods for customization.
  • Mechanism: Uses inheritance to allow subclasses to fill in the details of an algorithm.
  • Benefit: Enforces a consistent algorithm structure, reduces code duplication, and improves maintainability.
  • Trade-off: It's less flexible than the Strategy pattern because the algorithm's structure is fixed at compile time.

In our next lesson, we will cover the Visitor pattern. While Template Method uses inheritance to vary steps in an algorithm, Visitor offers a way to add new operations to an entire hierarchy of classes without modifying those classes. It provides a different and powerful way to handle operations on complex object structures.

Can't find a good explanation? Sign up and we'll make it for you

Sign up