Template Method Design Pattern in C# with Example

1. Definition

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses, and letting subclasses redefine certain steps of an algorithm without changing its structure.

2. Problem Statement

Consider a scenario where you're building a document converter that can convert documents to different formats. The process may involve steps like parsing the document, converting, and saving. If each of these steps is closely intertwined within a monolithic method, introducing a new conversion format could require modifying the main method, violating the Open/Closed principle.

3. Solution

The Template Method pattern suggests moving the invariant parts of the logic into a superclass, while the variable parts can be implemented in subclasses. The "template method" in the superclass should outline the algorithm, calling abstract primitive operations as well as concrete operations.

4. Real-World Use Cases

1. Compilers for different languages using a common structure for parsing, analyzing, and generating output.

2. Bread baking processes where the steps (like mixing, and baking) are the same, but the ingredients or temperature can vary.

3. Frameworks that provide architectural flow, but allow users to customize specific steps.

5. Implementation Steps

1. Analyze the target algorithm to see which steps are invariant and which are variants.

2. Define a new abstract base class with a template method.

3. Implement invariant steps in the base class.

4. Introduce abstract methods for the variant parts.

5. Subclasses will implement the abstract methods.

6. Implementation in C#

// Abstract class with the template method
public abstract class BreadMaker
{
    // The 'Template Method'
    public void MakeBread()
    {
        MixIngredients();
        Bake();
        Slice();
    }

    // Default implementation of invariant steps
    protected void MixIngredients()
    {
        Console.WriteLine("Gathering and mixing ingredients for the bread type.");
    }

    protected void Slice()
    {
        Console.WriteLine("Slicing the bread.");
    }

    // Abstract methods for variant steps
    protected abstract void Bake();
}

// Concrete class A
public class WhiteBreadMaker : BreadMaker
{
    protected override void Bake()
    {
        Console.WriteLine("Baking the white bread. (15 minutes)");
    }
}

// Concrete class B
public class WholeWheatBreadMaker : BreadMaker
{
    protected override void Bake()
    {
        Console.WriteLine("Baking the whole wheat bread. (25 minutes)");
    }
}

public class Program
{
    public static void Main()
    {
        BreadMaker whiteBreadMaker = new WhiteBreadMaker();
        whiteBreadMaker.MakeBread();

        Console.WriteLine();

        BreadMaker wholeWheatBreadMaker = new WholeWheatBreadMaker();
        wholeWheatBreadMaker.MakeBread();
    }
}

Output:

Gathering and mixing ingredients for the bread type.
Baking the white bread. (15 minutes)
Slicing the bread.

Gathering and mixing ingredients for the bread type.
Baking the whole wheat bread. (25 minutes)
Slicing the bread.

Explanation:

In this example, BreadMaker provides the template method MakeBread(), which follows the steps for making bread. While the methods MixIngredients and Slice are common to all bread types and are implemented in the base class, the Bake method is variable and is implemented in each subclass.

7. When to use?

1. When you want to let clients extend only particular steps of an algorithm, but not the whole algorithm or its structure.

2. When you have several classes that contain almost identical algorithms with some minor differences. The Template Method allows you to refactor the algorithm into a single template method in an abstract base class.


Comments