• Giacomo Debidda
    • Blog
    • Projects
    • About
    • Contact

Template Method pattern in Python

27 Jan 2017
  • design patterns
  • inversion of control
  • python

Table of Contents đź“‘
  1. # The Skeleton
  2. # A quick note about the ABC module.
  3. # The Customizable Parts
  4. # The Hollywood Principle
  5. # The client code
  6. # References

Behavioral design patterns are a family of patterns which focus on algorithms and the assignments of responsibilities between objects. They help in changing the behavior of the objects and reduce the coupling between them. In this article we will see a Python implementation of the Template Method pattern. Next time we will see the Strategy pattern.

Template Method defines an algorithm’s skeleton in a base class, and lets subclasses redefine certain steps of the algorithm. The skeleton stays the same for all subclasses, and it defines which methods to call and when to call them. Some methods in the base class are just placeholders (or hooks), and they have to be overridden in each subclass.

A typical implementation of this pattern consists in an abstract class for the base class, and one or more concrete subclasses. The abstract class has the following methods:

  1. one template method that calls one or more methods. Subclasses should not override this particular method, which defines the skeleton of the algorithm. This method gives the name to this pattern, so in this Python implementation I called it template_method.
  2. one or more abstract methods, which represent the customizable part of the algorithm. The abstract base class defines these methods, but they are just placeholders and have to be overriden by each subclass. Sometimes they are named “primitive operations”, “hooks” or “placeholders”. I called these methods do_step_1 and do_step_2.
  3. zero or more methods which are common in each subclass. These methods are implemented in the base class and should not be overridden in any subclass. In Java we could make these methods final. In Python we can place two underscore before the method name and “protect” them from being overridden by using private name mangling. The method can still be overriden by a subclass, but with no effect, because the name mangling replaces the original method name with the class name where the method is originally defined, plus the original method name itself. In the code below, __do_absolutely_this is one of such methods.
  4. one or more methods that have a default implementation in the base class, but that can be overridden by some sublasses. Here is the do_something method.

Private name mangling for the __do_absolutely_this method. The original class name is prepended to the method name. That’s why we see Algorithm__do_absolutely_this even when we look at the list of attributes of class AlgorithmA.

Private name mangling

# The Skeleton

Here is the abstract base class which defines the template_method.

import sys
from abc import ABC, abstractmethod


class Algorithm(ABC):

def template_method(self):
"""Skeleton of operations to perform. DON'T override me.

The Template Method defines a skeleton of an algorithm in an operation,
and defers some steps to subclasses.
"""

self.__do_absolutely_this()
self.do_step_1()
self.do_step_2()
self.do_something()

def __do_absolutely_this(self):
"""Protected operation. DON'T override me."""
this_method_name = sys._getframe().f_code.co_name
print('{}.{}'.format(self.__class__.__name__, this_method_name))

@abstractmethod
def do_step_1(self):
"""Primitive operation. You HAVE TO override me, I'm a placeholder."""
pass

@abstractmethod
def do_step_2(self):
"""Primitive operation. You HAVE TO override me, I'm a placeholder."""
pass

def do_something(self):
"""Hook. You CAN override me, I'm NOT a placeholder."""
print('do something')

# A quick note about the ABC module.

Sometimes in Python you create “abstract” methods this way:

def some_method_in_base_class(self):
raise NotImplementedError('Implement me in subclass')

However, you can still create instances of a subclass if you don’t override such method. You will simply get a NotImplementedError exception when you try to call that method on an instance of the subclass.

I like to use ABC because you cannot even instantiate a subclass of Algorithm if you don’t override all abstract methods.

# The Customizable Parts

Each concrete subclass have to override do_step_1 and do_step_2, because they are decorated with the @abstractmethod decorator from the ABC module. Each sublclass can override do_something, or it will use the default implementation provided by the base class.

class AlgorithmA(Algorithm):

def do_step_1(self):
print('do step 1 for Algorithm A')

def do_step_2(self):
print('do step 2 for Algorithm A')


class AlgorithmB(Algorithm):

def do_step_1(self):
print('do step 1 for Algorithm B')

def do_step_2(self):
print('do step 2 for Algorithm B')

def do_something(self):
print('do something else')

# The Hollywood Principle

Here comes the interesting part…

Most of the time a subclass calls the methods of its parent, so the flow of control goes from the subclass to its parent. However, in template_method the flow goes from the base class to a subclass, a principle called Inversion of Control (IoC).

IoC, also called Hollywood Principle - Don’t call us, we’ll call you - decouples the execution of a task from its implementation. The client code doesn’t call directly the methods responsible for the implementation (do_step_1 and do_step_2), but calls a method provided by the base class (template_method), which calls the implementation methods itself.

Capture the abstraction in an interface, and bury the implementation details in its subclasses.

This situation is quite common in frameworks. Each framework designs a common interface that implements the invariant pieces of a system’s architecture, and defines placeholders for all customizable parts. Most of the time it’s the framework itself that calls the methods supplied by the user.

# The client code

Finally, here is the client code…

def main():
print('Algorithm A')
a = AlgorithmA()
a.template_method()

print('\nAlgorithm B')
b = AlgorithmB()
b.template_method()

if __name__ == '__main__':
main()

and the output:

>>> Algorithm A
>>> AlgorithmA.__do_absolutely_this
>>> do step 1 for Algorithm A
>>> do step 2 for Algorithm A
>>> do something

>>> Algorithm B
>>> AlgorithmB.__do_absolutely_this
>>> do step 1 for Algorithm B
>>> step 2 for Algorithm B
>>> something else

You need the code? Grab it here!

# References

Here are some additional resources you might find useful:

  • Template Method on Sourcemaking.com
  • Martin Fowler’s article on Inversion of Control

  • design patterns
  • inversion of control
  • python
  • RSS
  • GitHub
  • Twitter
  • Linkedin
  • Stack Overflow
Copyright © 2020 – 2022 Giacomo Debidda – All rights reserved