Template Method Design Pattern: A  Simple Guide

Template Method Design Pattern: A Simple Guide

18 Sep 2024
Intermediate
37K Views
24 min read
Learn with an interactive course and practical hands-on labs

⭐ .NET Design Patterns Course: Design Patterns in C# Online Training

Template Method Design Pattern

Template Method Design Pattern is a type of behavioral design pattern that comes under Gangs of Four Design Patterns. Defining the general framework of an algorithm in the superclass allows subclasses to override individual stages without affecting the algorithm's overall structure.

In the Design pattern tutorial, we will explore about what is template method design pattern?, components of template method design pattern, structure of template method design pattern, implementation of template method design pattern, real-world example, connections with other design patterns, advantages and disadvantages of Template method design pattern, applications and many more.

What is the Template method Design Pattern?

Template Method Design Pattern defines the structure of an algorithm in a base class, allowing subclasses to override specific steps without changing the overall algorithm. It ensures a consistent algorithm while enabling flexibility in its implementation details.

  • The parent class maintains the general hierarchy and flow of the algorithm.
  • A template refers to a prepared format, such as an HTML template with a predetermined format. The template method pattern uses a similar preset structure technique called a template method, which consists of phases.
  • These actions might be an abstract procedure that its subclasses carry out.
  • This is among the simplest to comprehend and implement. This design approach reduces code duplication and is often used in framework development.
Read More:
Types of Design Patterns
IoC Container and DI Container: An Easy Guidel
Different Types of Software Design Principles

Components of Template Method Design Pattern

There are four components in the Template method design pattern that are:

  • Abstract Class (or Interface)
  • Template Method
  • Abstract (or Hook) Methods
  • Concrete Subclasses

Components of Template Method Design Pattern

1. Abstract Class (or Interface)

  • Defines the template method outlining the algorithm's structure.
  • Includes abstract methods for steps that vary in different implementations.
  • Provides hook methods with default behavior that can be overridden.
  • Ensures a consistent sequence of operations across subclasses.
  • Promotes code reuse by handling common parts of the algorithm.

2. Template Method

  • describes the general layout and flow of the algorithm.
  • Calls on abstract methods that subclasses have implemented.
  • May invoke hook methods with subclasses' ability to override the default behavior.
  • Allows for customization of individual phases while ensuring a consistent order of activities.
  • Reduces code duplication by encapsulating the algorithm's common phases.

3. Abstract (or Hook) Methods

  • Represent steps of the algorithm that vary among implementations.
  • Declared in the abstract class or interface and must be implemented by subclasses.
  • Allow subclasses to define specific behavior for different parts of the algorithm.
  • Provide flexibility while maintaining the overall structure defined by the template method.
  • It can be overridden to customize or extend the behavior of the algorithm.

4. Concrete Subclasses

  • Implement the abstract methods defined in the base class or interface.
  • Provide specific details or variations for the algorithm steps.
  • Adhere to the structure outlined by the template method in the base class.
  • Optionally override hook methods to customize default behavior.
  • Ensure that the algorithm defined in the base class functions correctly with the provided implementations.

Structure of Template Method Design Pattern

Structure of Template Method Design Pattern
  1. Both the actual template method that calls these methods in a certain sequence and the methods that function as stages in an algorithm are declared in the Abstract Class. The steps might have a default implementation or be declared abstract.
  2. The template method itself cannot be overridden by Concrete Classes, but all of the phases may.

Implementation of Template Method Design Factory

The implementation of the Template method design pattern is as follows:

1. Abstract Base Class

  • Create an abstract class that defines the template method.
  • This template method will outline the steps of the algorithm, some of which will be abstract (to be implemented by subclasses).

2. Define Template Method

  • The template method is the final method in the abstract class that provides the algorithm's structure.
  • It is called abstract methods, some of which are implemented by subclasses, and it may be called hook methods for optional customization.

3. Abstract and Hook Methods

  • Define abstract methods for steps that need to be customized by subclasses.
  • Optionally, provide hook methods with default implementations that subclasses can override if needed.

4. Concrete Subclasses

  • Create concrete subclasses that extend the abstract class and implement the abstract methods.
  • These subclasses define specific behaviors for the algorithm's variable steps while adhering to the template's overall structure.

Real-world Example of Template Method Design Pattern

Beverage Preparation (Tea and Coffee)

Both tea and coffee require boiling water, brewing the drink, pouring it into a cup, and optionally adding condiments. The common steps can be handled by the template method, while the variations (like brewing tea vs. coffee) are handled by the subclasses.

Steps of the Process:

  1. Boil Water
  2. Brew (Tea/Coffee)
  3. Pour into cup
  4. Add Condiments (optional)
using System;

abstract class Beverage
{
    // Template method
    public void PrepareRecipe()
    {
        BoilWater();
        Brew();
        PourInCup();
        AddCondiments();
    }

    // Common step for all beverages
    public void BoilWater()
    {
        Console.WriteLine("Boiling water");
    }

    // Common step for all beverages
    public void PourInCup()
    {
        Console.WriteLine("Pouring into cup");
    }

    // Abstract methods to be implemented by subclasses
    protected abstract void Brew();
    protected abstract void AddCondiments();
}

class Tea : Beverage
{
    protected override void Brew()
    {
        Console.WriteLine("Steeping the tea");
    }

    protected override void AddCondiments()
    {
        Console.WriteLine("Adding lemon");
    }
}

class Coffee : Beverage
{
    protected override void Brew()
    {
        Console.WriteLine("Dripping coffee through filter");
    }

    protected override void AddCondiments()
    {
        Console.WriteLine("Adding sugar and milk");
    }
}

class Program
{
    static void Main()
    {
        Beverage tea = new Tea();
        tea.PrepareRecipe();

        Beverage coffee = new Coffee();
        coffee.PrepareRecipe();
    }
}            

from abc import ABC, abstractmethod

class Beverage(ABC):
    # Template method
    def prepare_recipe(self):
        self.boil_water()
        self.brew()
        self.pour_in_cup()
        self.add_condiments()

    # Common step for all beverages
    def boil_water(self):
        print("Boiling water")

    # Common step for all beverages
    def pour_in_cup(self):
        print("Pouring into cup")

    @abstractmethod
    def brew(self):
        pass

    @abstractmethod
    def add_condiments(self):
        pass

class Tea(Beverage):
    def brew(self):
        print("Steeping the tea")

    def add_condiments(self):
        print("Adding lemon")

class Coffee(Beverage):
    def brew(self):
        print("Dripping coffee through filter")

    def add_condiments(self):
        print("Adding sugar and milk")

if __name__ == "__main__":
    tea = Tea()
    tea.prepare_recipe()

    coffee = Coffee()
    coffee.prepare_recipe()
            

abstract class Beverage {
    // Template method
    public final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    // Common step for all beverages
    public void boilWater() {
        System.out.println("Boiling water");
    }

    // Common step for all beverages
    public void pourInCup() {
        System.out.println("Pouring into cup");
    }

    // Abstract methods to be implemented by subclasses
    abstract void brew();
    abstract void addCondiments();
}

class Tea extends Beverage {
    @Override
    public void brew() {
        System.out.println("Steeping the tea");
    }

    @Override
    public void addCondiments() {
        System.out.println("Adding lemon");
    }
}

class Coffee extends Beverage {
    @Override
    public void brew() {
        System.out.println("Dripping coffee through filter");
    }

    @Override
    public void addCondiments() {
        System.out.println("Adding sugar and milk");
    }
}

public class Main {
    public static void main(String[] args) {
        Beverage tea = new Tea();
        tea.prepareRecipe();

        Beverage coffee = new Coffee();
        coffee.prepareRecipe();
    }
}
            

abstract class Beverage {
    // Template method
    public prepareRecipe(): void {
        this.boilWater();
        this.brew();
        this.pourInCup();
        this.addCondiments();
    }

    // Common step for all beverages
    private boilWater(): void {
        console.log("Boiling water");
    }

    // Common step for all beverages
    private pourInCup(): void {
        console.log("Pouring into cup");
    }

    // Abstract methods to be implemented by subclasses
    protected abstract brew(): void;
    protected abstract addCondiments(): void;
}

class Tea extends Beverage {
    protected brew(): void {
        console.log("Steeping the tea");
    }

    protected addCondiments(): void {
        console.log("Adding lemon");
    }
}

class Coffee extends Beverage {
    protected brew(): void {
        console.log("Dripping coffee through filter");
    }

    protected addCondiments(): void {
        console.log("Adding sugar and milk");
    }
}

const tea = new Tea();
tea.prepareRecipe();

const coffee = new Coffee();
coffee.prepareRecipe();
            

Output

Boiling water
Steeping the tea
Pouring into cup
Adding lemon
Boiling water
Dripping coffee through filter
Pouring into cup
Adding sugar and milk

Explanation

  • The Beverage class defines the template method prepareRecipe(), which outlines the steps for making a beverage.
  • The abstract methods brew() and addCondiments() are implemented differently by the subclasses Tea and Coffee.
  • The common steps (boiling water and pouring into a cup) are handled in the base class, ensuring consistency across beverages.

When to use Template Method Design Pattern

Here are the several aspects where you should use this design pattern:

1. Common Algorithm with Variations

When you have an algorithm with common steps, some steps need to be customized by subclasses. For example, making different beverages (tea and coffee) follows a similar process but differs in some steps.

2. Code Reusability

When you want to avoid code duplication, you can do so by encapsulating the shared steps of an algorithm in a base class and allowing subclasses to implement the specific steps.

3. Consistent Algorithm Structure

When you need to ensure that the overall structure of the algorithm remains consistent across multiple subclasses while allowing variations in specific steps.

4. Frameworks and Libraries

When building a framework where the high-level flow (template method) should remain the same, but users can extend and provide their own implementations for certain parts of the process (via abstract methods).

5. Hook Methods for Flexibility

When you want to allow optional customization of some steps by providing default behavior in the base class that can be overridden by subclasses if needed.

When not to use Template Method Design Pattern

Here are the several reasons that you should not use this design pattern:

1. Algorithm is Simple:If the algorithm is straightforward and doesn't need variations, using this pattern can add unnecessary complexity.

2. Few or No Shared Steps:When there are minimal common steps between subclasses, it’s better to implement them separately without forcing a common structure.

3. Frequent Changes in Algorithm Structure:If the overall structure of the algorithm is likely to change frequently, the pattern becomes rigid and hard to maintain.

4. Prefer Composition Over Inheritance:When composition (using objects) is a better fit than inheritance, using the Template Method may limit flexibility.

Comparison with Other Design Patterns

1. Template Method vs. Strategy

  • Template: Fixed algorithm structure with customizable steps.
  • Strategy: Swappable algorithms, no fixed structure.

2. Template Method vs. Factory Method

  • Template: Defines the process flow; subclasses modify steps.
  • Factory: Focuses on creating objects; subclasses choose the object type.

3. Template Method vs. Observer

  • Template: Subclasses customize algorithm steps.
  • Observer: Notifies multiple objects about changes, but there are no fixed steps.

4. Template Method vs. Decorator

  • Template: Customizes steps within a defined process.
  • Decorator: Adds new functionality to objects dynamically.

5. Template Method vs. Builder

  • Template: Fixed algorithm with flexible steps.
  • Builder: Flexible construction of complex objects step by step.

Advantages of Template Method Design Pattern

  • It provides a common algorithm framework that encourages the reuse of code.
  • Subclasses minimize redundancy by customizing just particular stages.
  • Increases adaptability by permitting changes to certain techniques.
  • Maintains a uniform process between various classes.
  • Sticks to the "open for extension, closed for modification" principle.
  • Centralizes the algorithm within the basic class, making maintenance easier.

Disadvantages of Template Method Design Pattern

  • Base and subclasses are closely correlated. Therefore, modifications to one class will impact all of the subclasses.
  • This might result in increased code complexity as the class hierarchy expands.
  • Restricted flexibility due to the predetermined overall structure of the method.
  • Makes the base class responsible for both the specific steps and the algorithm flow, which is against the Single Responsibility Principle.
  • If several variants are required, subclassing may get difficult.
Read More:
Understanding MVC, MVP, and MVVM Design Patterns
Top 50 Java Design Patterns Interview Questions and Answers
.Net Design Patterns Interview Questions, You Must Know!
Most Frequently Asked Software Architect Interview Questions and Answers
Conclusion

In conclusion, the Template Method Design Pattern ensures consistent algorithms with customizable steps but may cause tight coupling and complexity in subclasses. It’s best used when the algorithm structure needs to stay fixed with some variations. To master design patterns, enroll in ScholarHat's Master Software Architecture and Design Certification Training.

FAQs

Changes to the overall algorithm require modifications in the base class, but changes to specific steps can be handled by altering subclasses. 

An example is a Document class where open(), save(), and print() methods are defined. The save() method’s algorithm is fixed, but the way data is saved (e.g., to a file or database) can be customized by subclasses. 

By centralizing the algorithm’s structure in a base class, changes to the common process need only be made in one place, improving maintainability and consistency. 

Yes, it is commonly used with inheritance where the base class provides the template and subclasses extend or modify specific steps. 
Share Article
About Author
Shailendra Chauhan (Microsoft MVP, Founder & CEO at Scholarhat by DotNetTricks)

Shailendra Chauhan, Founder and CEO of ScholarHat by DotNetTricks, is a renowned expert in System Design, Software Architecture, Azure Cloud, .NET, Angular, React, Node.js, Microservices, DevOps, and Cross-Platform Mobile App Development. His skill set extends into emerging fields like Data Science, Python, Azure AI/ML, and Generative AI, making him a well-rounded expert who bridges traditional development frameworks with cutting-edge advancements. Recognized as a Microsoft Most Valuable Professional (MVP) for an impressive 9 consecutive years (2016–2024), he has consistently demonstrated excellence in delivering impactful solutions and inspiring learners.

Shailendra’s unique, hands-on training programs and bestselling books have empowered thousands of professionals to excel in their careers and crack tough interviews. A visionary leader, he continues to revolutionize technology education with his innovative approach.
Accept cookies & close this