Jonathan Boccara's blog

Design Patterns VS Design Principles: Template Method

Published November 17, 2021 - 0 Comments

In today’s episode of “Design Pattens VS Design Principles” series, we relate the Template Method design patterns to more general design principles. We’re showing how it relates to the Polymorphism design principle.

The GoF Meets the GRASP

If you’re just joining us in the series, here is what it’s about: we’re going over each of the 23 design patterns coming from the GoF’s seminal Design Patterns book, and for each pattern we’re trying to see to which GRASP design principle it relates the most.

GRASP are high level design principles that are explained in Craig Larman’s Applying UML and Patterns book.

The GRASP principles look like this (excluding “Managing complexity”, hierarchy mine):

design principles hierarchy

The purpose of this series is to:

  • understand the essence of each GoF design pattern,
  • better understand the GRASP design principle,
  • be able to take better decisions when it comes to structuring our code, to make it more expressive and robust.

Today, we focus on the Template Method.

Template Method

First off, let’s mention that the Template Method design pattern has nothing to do with C++ templates. Actually, there is an implementation of this design pattern in C++ that uses templates, but using templates is more an implementation detail rather than the essence of this pattern.

Template Method has even nothing to do with C++ in particular, and can be implemented in other languages that don’t support templates.

Template Method consists in having a piece of code that has one or more customisation points.

For example, in the following piece of code:

doX();
doY();
doZ();

Template Method can consist in making doY() customisable.

The examples where this is useful are countless. A simple example is when doX() and doZ() perform logging, and doY() does the actual job:

std::cout << "Task in progress... "; // this is doX()
doTheTask();                         // this is doY()
std::cout << " ...done.\n";          // this is doZ()

Instead of letting clients call doTheTask directly, we force them to go through that code so that we make sure that logging is executed.

And to perform logging around any sort of task, we make doTheTask() customisable.

Customisation points

How? By using polymorphism. In the GoF book, the authors suggest to use runtime polymorphism, with inheritance and virtual member functions.

In our example, we would then have a base class that would look like this:

class Task
{
public:
    void run();
    virtual ~Task() = 0;
private:
    virtual void doTheTask() const = 0;
};

It is the non-virtual run member function that contains the Template Method design pattern:

void Task::run()
{
    std::cout << "Task in progress... ";
    doTheTask();
    std::cout << " ...done.\n";
}

A given task has its own class, that implements the Task base class:

class MyTask : public Task
{
private:
    void doTheTask() const override;
};

(In case you’re wondering, we can indeed override private virtual methods from the base class).

Now if you have code that uses the Task interface, you’re guaranteed that logging will be executed without any additional code from the classes that implement the concrete tasks.

NVI

While we’re talking about this, note that the Template Method design pattern is a way to implement the Non Virtual Interface, or NVI, pattern.

NVI consists in exposing only non-virtual methods in the public section of a base class. Those methods themselves call private virtual methods, that are implemented in derived classes.

The NVI pattern recognises that the public interface of a base class should not be coupled to the implementation of the virtual methods. Indeed, the former represents the interface, and the latter represents some implementation steps.

Some developers go as far as never defining a member method public and virtual at the same time. Said differently, they use NVI all the time.

NVI is a way to implement the Template Method design pattern. When the NVI public non virtual method simply calls the private virtual method, without any additional treatment, this can be seen as a degenerate case of Template Method.

Template method with C++ templates

Inheritance and virtual tables are just one way of implementing polymorphism.

We can also use C++ templates to implement polymorphism. Templates create another type of polymorphism, that is resolved at compile-time. This is whole other topic, so if the previous sentence doesn’t make perfect sense, it’s not a problem. We’ll come back to this in another post.

An implementation of the Template Method design pattern with C++ templates would look like this:

template <typename Task>
void runTask(Task const& task)
{
    std::cout << "Task in progress... ";
    task.doTheTask();
    std::cout << " ...done.\n"; 
}

In this case, there is no base class any more. We can pass MyTask, that used to be the derived class in our previous example, to the runTask template function:

auto myTask = MyTask{};
runTask(myTask);

Now doTheTask member function needs to be public:

class MyTask : public Task
{
public:
    void doTheTask() const override;
};

Indeed, in the previous implementation using inheritance, the code using the Template Method design pattern (the base class) had access to the implementation of the task via the redirection of virtual member functions.

Now that the code using the Template Method design pattern is in a free function, it has to call the public interface of MyTask, so its method has to be public (unless runTask is made a friend class).

Design principle

Which one of the GRASP design principles does the Template Method design pattern relate to the most?

This is an open question, that you can answer in the comments section.

I would argue that it relates the most to Polymorphism. Indeed, the essence of the Template Method design pattern is to have a part of a piece of code that can be executed in different ways, which can vary independently from that piece of code. This is exactly what Polymorphism allows to do.

Note that Template Method looks like an extension of the Strategy design pattern, because the customisation point of the Template Method code implements a Strategy pattern. Code using Template Method can have several customisation points. Each one would be a Strategy pattern.

Note that we classified Strategy as related to Polymorphism too.

What do  you think?

I initially intended to cover in this post Template Method and Visitor, the last two so-called “Behavioural design patterns”.

But since we’ve already spent a bit of time getting in the details of Template Method in order to better understand it, and since Visitor also has quite a few design aspects to examine, we’ll leave Visitor for next time.

In summary of this post, Template Method is a way to achieve the GRASP principle Polymorphism.

Or is it? If you agree or disagree, please leave your opinion in the discussion below.

You will also like

Don't want to miss out ? Follow:   twitterlinkedinrss
Share this post!Facebooktwitterlinkedin