This is part of a series of posts demonstrating software design patterns using C# and .NET. The patterns are taken from the book Design Patterns by the Gang of Four. Here's the series index page.

What Is This Pattern?

The Template Method design pattern defines the outline or skeleton of an operation, but leaves the specific steps involved to be defined by subclasses.

In other words, the Template Method pattern defines in what order certain steps should occur, but can optionally leave the specific details of those steps to be implemented by other classes. Whereas Factory Method did something similar with creating objects, Template Method does this with the behavior of those objects.

The Rundown

  • Type: Behavioral
  • Useful? 4/5 (Very, with some caveats)
  • Good For: Creating an outline of an algorithm but letting specific steps be implemented by other classes.
  • Example Code: On GitHub

The Participants

  • The AbstractClass defines a set of abstract operations which can (optionally) be implemented by ConcreteClass objects. It also implements a template method which controls the order in which those abstract operations occur.
  • The ConcreteClass objects implement the operations defined by the AbstractClass.

A Delicious Example

To properly demo this design pattern, let's talk about something humanity has been doing for 30,000 years: baking bread.

A United States Navy sailor pulls a tray of freshly-baked bread out of an oven

There are easily hundreds of types of bread currently being made in the world, but each kind involves specific steps in order to make them. While acknowledging that this doesn't necessarily cover all kinds of bread that are possible to make, let's say that there are three basic steps in making bread:

  1. Mix the ingredients together.
  2. Bake the mixture.
  3. Slice the resulting bread.

We want to model a few different kinds of bread that all use this same pattern, which (no surprise) is a good fit for the Template Method design pattern.

First, let's create an AbstractClass Bread which represents all breads we can bake:

/// <summary>
/// The AbstractClass participant which contains the template method.
/// </summary>
abstract class Bread  
{
    public abstract void MixIngredients();

    public abstract void Bake();

    public virtual void Slice() 
    {
        Console.WriteLine("Slicing the " + GetType().Name + " bread!");
    }

    // The template method
    public void Make()
    {
        MixIngredients();
        Bake();
        Slice();
    }
}

Notice that the MixIngredients() and Bake() methods are abstract, while the Slice() method is virtual. This is intentional: the method by which you slice bread is not likely to change depending on the kind of bread you make. Further, the Make() method is the Template Method that gives this pattern its name.

Let's extend this example by implementing several ConcreteClass objects for different types of bread:

class TwelveGrain : Bread  
{
    public override void MixIngredients()
    {
        Console.WriteLine("Gathering Ingredients for 12-Grain Bread.");
    }

    public override void Bake()
    {
        Console.WriteLine("Baking the 12-Grain Bread. (25 minutes)");
    }
}

class Sourdough : Bread  
{
    public override void MixIngredients()
    {
        Console.WriteLine("Gathering Ingredients for Sourdough Bread.");
    }

    public override void Bake()
    {
        Console.WriteLine("Baking the Sourdough Bread. (20 minutes)");
    }
}

class WholeWheat : Bread  
{
    public override void MixIngredients()
    {
        Console.WriteLine("Gathering Ingredients for Whole Wheat Bread.");
    }

    public override void Bake()
    {
        Console.WriteLine("Baking the Whole Wheat Bread. (15 minutes)");
    }
}

Once we've defined a few types of bread, we can simulate making them in our Main() method, like so:

static void Main(string[] args)  
{
    Sourdough sourdough = new Sourdough();
    sourdough.Make();

    TwelveGrain twelveGrain = new TwelveGrain();
    twelveGrain.Make();

    WholeWheat wholeWheat = new WholeWheat();
    wholeWheat.Make();

    Console.ReadKey();
}

It's just that simple. In fact, Template Method is (arguably) the simplest and most flexible of all the behavioral methods. Wanna guess why I'm writing about it first?

Will I Ever Use This Pattern?

Almost certainly. I'd be willing to bet that most of you dear readers have already used this pattern and may not have known what it was called. This pattern is extremely common, flexible, and useful for many different applications and scenarios.

...But. It's not without problems. Jimmy Bogard explains:

"While some gravitate towards the Singleton pattern to abuse after they learn the GoF patterns, that wasn’t the case for me. Instead, I fell in love with the Template [Method] Pattern. But there’s a problem with [this] pattern as the golden hammer for every incidence of duplication we find in our application. The Template Method favors inheritance over composition."

And, to be fair, he's right. Template Method forces a class to inherit from a class rather than promoting object composition. If we're looking for strict-object-oriented design, Template Method could be better replaced by other patterns we've yet to cover, such as Strategy or Command.

But I'm not willing to go as far as saying "don't use Template Method." As with all the other patterns, their applications depend on what problem you need to solve and how you want to do so. Template Method is prone to over-use, so be careful with it.

Summary

The Template Method design pattern allows for an object to set up a skeleton of an algorithm but leave the implementation details up to the concrete classes to implement.

As always, I like to provide code with my tutorials, so the repository for this pattern is over on GitHub and contains all of the sample code used here.

Happy Coding!

Get My eBook FREE!

Did you enjoy this post? This article and 21 others are also in my free eBook, "The Daily Design Pattern", which you can get just by signing up for my email list.