Understanding the Template Method Pattern in Python

Introduction

I found myself wanting to write an extensible class for handling a few fancy new APIs out there. There are a ton that do the same thing, and the field is constantly evolving, so it's useful to be able to easily switch from one to the next.

I chose the Template Method design pattern. This is useful when you have a series of steps that need to be executed in a specific order, but the implementation of some steps may vary.

What is the Template Method Pattern?

The Template Method pattern defines the skeleton of an algorithm in a base class but lets subclasses override specific steps of the algorithm without changing its structure. It's called "template method" because it defines a template for an algorithm's steps.

A Simple Example: Coffee and Tea

Let's illustrate this pattern with a simple example of brewing beverages. We'll create a base class for brewing beverages and then implement specific classes for coffee and tea.

from abc import ABC
from abc import abstractmethod


class Beverage(ABC):
    def prepare(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 Coffee(Beverage):
    def brew(self):
        print("Dripping coffee through filter")

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


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

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

# Usage
coffee = Coffee()
tea = Tea()

print("Making coffee:")
coffee.prepare()

print("\nMaking tea:")
tea.prepare()

In this example, Beverage is our abstract base class that defines the template method prepare(). This method outlines the steps for preparing a beverage, but leaves the implementation of brew() and add_condiments() to the subclasses.

Benefits of the Template Method Pattern

  1. Reduce duplication by implementing the common parts of the algorithm in the base class.
  2. Subclasses can easily override certain steps without changing the overall algorithm structure.
  3. The base class handles the algorithm's structure, while the subclasses focus on the specific details of each step.

As long as you're clear on the data structure you want your methods to return, you can swap in many different subclasses.

Real-World Applications

The Template Method pattern is widely used in frameworks and libraries. For instance:

  • In web frameworks, the base controller class might define a template method for handling HTTP requests, with subclasses implementing specific behaviors for different routes.
  • In testing frameworks, the setup-run-teardown process is often implemented as a template method, allowing test classes to override specific parts of this process.
  • When calling external services, your template transforms the API response into the data structure your application is expecting.

Example Template Class

You might want to call a nutrition facts API to get info about food, but not feel locked in to a single API provider. You could write a NutritionFacts base class which outlines the get_nutrition_facts method and returns a Django NutritionInfo model object, outlining the fat, carbohydrates, and protein in a particular meal.

Then, when you're fed up (get it?) with the Spoonacular API, you can implement the Edamam API with .

Conclusion

The Template Method pattern allows for the creation of flexible and reusable code structures, making it easier to implement variations of an algorithm while keeping the overall process consistent. By understanding and applying this pattern, you can write more maintainable and extensible code in your Python projects.

Remember, while design patterns like the Template Method are useful, they should be applied judiciously. If you're only making one class, it might not be helpful to make that inherit from a base class.

Best of luck in your design endeavors.

Get Notified of New Posts

Sign up for the newsletter and I'll send you an email when there's a new post.