Software development is not an easy task. There are many problems a developer faces while creating solutions to real-world problems. Some of these problems repeatedly occur, so GoF design patterns came into being to save time and effort.
A GoF design patterns provide a tried and tested architecture or design to solve commonly occurring problems. One of these patterns, the Template Method pattern, helps you define flexible algorithms.
Template Method design pattern is a behavioral design pattern that defines the skeleton of an algorithm in a superclass, but lets subclasses override specific algorithm steps. You can use it to create flexible algorithms. It also prevents subclasses from modifying the algorithm in incompatible ways.
In this post, you will learn the basics of the Template Method with the help of real-world code examples. You will also be able to identify this pattern’s use cases and applicability to resolve your programming problems.
What is the Template Method design pattern?
Frameworks are an essential aspect of software design. A framework divides the solution code into two parts: a variant part and an invariant part, allowing clients to add desired specifications. That is why it is common to implement frameworks using the Template Method.
The Template Method design pattern is a behavioral design pattern that defines the skeleton of an algorithm in a base class but leaves the implementation of some steps to subclasses. This allows subclasses to override the steps they want to change without changing the algorithm. The Template Method design pattern is often used in frameworks, where the algorithm is defined in a base class, but the framework user provides the implementation of each step.
The base class is an abstract class that defines all the methods required for the algorithm implementation and determines the order in which each method should be called. On the other hand, the child classes can override some parts of the algorithm according to the client’s requirements.
When to use the Template Method design pattern?
There are several use cases where Template Method is especially useful:
- when the algorithm has variant and invariant parts
- when localizing common behavior among classes is the goal
- when subclasses need to be controlled.
Let’s dive a little bit deeper into each use case.
When the algorithm has variant and invariant parts
With the help of the Template Method, programmers can represent the invariant part of the algorithm only once, while multiple subclasses can represent the variant behavior. This results in a better program structure and space optimization.
Take, for instance, the procedure of sorting arrays. For any random array of numbers having a specific length, the program requires an array as an input and displays the resultant sorted array as an output on the screen. These are the non-varying parts of the algorithm that go directly into the parent class.
However, there are several methods of comparison to sort an array, such as bubble sort, selection sort, and insertion sort. Therefore, there will be three child classes, each implementing a different comparison method.
When localizing the common behavior among classes is the goal
Instead of repeating the same code blocks in multiple classes, their common behavior should be localized to a single-parent class.
If an algorithm already exists, you can refactor it by representing common code snippets into separate operations and calling them from single or multiple parent classes, known as the template classes.
A real-world example of such a case is brewing different brands of coffee. For any coffee brand, the initial steps should be the same: boil water, and add milk and sugar. However, in the last step, the coffee powder should be of a specific brand. This way, instead of implementing two classes with repeating steps, the initial stages can go to the parent class, whereas the child classes should only contain the coffee powder method.
When subclass extensions need to be controlled
The Template Method consists of statements called ‘hooks.’ These statements, defined in the base class, can either carry a default implementation or an empty body. Users may choose to override this behavior in the subclasses or leave it at doing nothing. In this way, extensions occur only at certain specific points where the hooks are called.
Who are the participants of the Template Method pattern? – C# Structural code
The Template Method design pattern is one of the most straightforward behavioral design patterns, with only two participants:
- AbstractClass: This class consists of a method called the TemplateMethod, which defines the order and outline of the algorithm. The TemplateMethod is final and cannot get overridden in any case. In this way, the structure of the algorithm always remains intact. The primitive operations defined in this class have implementations in the subclasses.
- ConcreteClass: This class specifies and refines the algorithm by redefining or implementing the abstract operations defined in the parent class.
The following image shows the Template Method pattern UML class diagram.
Here is an implementation of the Template Method, according to its UML structure:
abstract class AbstractClass
{
public void TemplateMethod()
{
PrimitiveOperation1();
PrimitiveOperation2();
ChildOperation1();
Hook();
ChildOperation2();
}
protected void PrimitiveOperation1()
{
Console.WriteLine("PrimitiveOperation1 with definition " +
"in Template Method");
}
protected void PrimitiveOperation2()
{
Console.WriteLine("PrimitiveOperation2 with definition " +
"in Template Method");
}
protected abstract void ChildOperation1();
protected abstract void ChildOperation2();
protected virtual void Hook()
{
//Empty body
}
}
class ConcreteClass1 : AbstractClass
{
protected override void ChildOperation1()
{
Console.WriteLine("Operation 1 Implementation " +
"in ConcreteClass1");
}
protected override void ChildOperation2()
{
Console.WriteLine("Operation 2 Implementation " +
"in ConcreteClass1");
}
protected override void Hook()
{
Console.WriteLine("Hook Overriding in ConcreteClass1");
}
}
The usage is as follows:
AbstractClass templateMethodClass = new ConcreteClass1();
templateMethodClass.TemplateMethod();
The output of this code representing the Template Method will be:
PrimitiveOperation1 with definition in Template Method
PrimitiveOperation2 with definition in Template Method
Operation 1 Implementation in ConcreteClass1
Hook Overriding in ConcreteClass1
Operation 2 Implementation in ConcreteClass1
You can see an implementation of the Template Method design pattern in this C# code. First, the code creates a parent class and defines the TemplateMethod. This method determines all the operations required for the algorithm or, in other words, creates a skeleton of the algorithm.
Apart from this method, there are implementations of PrimitiveOperation1 and PrimitiveOperation2 in the AbstractClass, showing that this part is common to all child classes. The overwrite-able Hook has an empty body in the main class.
Following the AbstractClass is a single ConcreteClass that carries implementations of the remaining operation, namely, PrimitiveOperation1, PrimitiveOperation2, and Hook. This class refines the algorithm further by making additions to the variant code section.
Note how the output occurs in the order in which the definitions of operations are present in the TemplateMethod. Hence, the template method inside an abstract class also determines the sequence of the algorithm.
The Hook implementation is optional and may or may not be present in the ConcereteClass. There can be multiple ConcreteClasses. However, the output of PrimitiveOperation1 and PrimitiveOperation2 will be common to all these subclasses.
Template Method pattern – Real-world example in C#
The Template Method design pattern reduces code redundancy in the real world by removing duplications. Let’s see the example of the tea-making algorithm using two different tea brands. See the code for it below.
public abstract class TeaTemplate
{
public void TeaTemplateMethod()
{
WaterAddition();
MilkAddition();
AddingTeaLeaves();
SugarAddition();
Console.WriteLine(this.GetType().Name +
" is Ready to Be Served");
}
protected abstract void WaterAddition();
protected abstract void MilkAddition();
protected abstract void AddingTeaLeaves();
protected virtual void SugarAddition()
{
Console.WriteLine("Sugar Added to Taste");
}
}
public class LiptonTea : TeaTemplate
{
protected override void WaterAddition()
{
Console.WriteLine("Tea Started");
}
protected override void MilkAddition()
{
Console.WriteLine("Adding Milk in Boiled Water");
}
protected override void AddingTeaLeaves()
{
Console.WriteLine("Lipton Tea Added for " +
"the Color and Flavor");
}
protected override void SugarAddition()
{
Console.WriteLine("Sugar Not Used");
}
}
public class TetleyTea : TeaTemplate
{
protected override void WaterAddition()
{
Console.WriteLine("Tea Started");
}
protected override void MilkAddition()
{
Console.WriteLine("Adding Milk in Boiled Water");
}
protected override void AddingTeaLeaves()
{
Console.WriteLine("Tetley Tea Added for " +
"the Color and Flavor");
}
}
The usage for the above code is given as:
Console.WriteLine("Preparing Tea with Lipton\n");
TeaTemplate tea = new LiptonTea();
tea.TeaTemplateMethod();
Console.WriteLine();
Console.WriteLine("Preparing Tea with Tetley\n");
tea = new TetleyTea();
tea.TeaTemplateMethod();
Console.Read();
The output of the code will be:
Preparing Tea with Lipton
Tea Started
Adding Milk in Boiled Water
Lipton Tea Added for the Color and Flavor
Sugar Not Used
LiptonTea is Ready to Be Served
Preparing Tea with Tetley
Tea Started
Adding Milk in Boiled Water
Tetley Tea Added for the Color and Flavor
Sugar Added to Taste
TetleyTea is Ready to Be Served
In this example, two concrete classes with methods and hooks are defined in the abstract class. Each concrete class outputs a step in the tea preparation process. The action of sugar addition is not mandatory for tea, and many people can choose to go without it. Therefore, the SugarAddition is a hook method, which can get overridden if the need arises.
By default, after the tea has gained flavor, the person making it would add the sugar to taste. However, a patient with diabetes, or someone who does not like sugar, can stop the person from adding it. In this way, they have no sugar in their tea. Resultantly, anyone can change the default behavior of this hook.
Advantages and Disadvantages of using Template Method Pattern
The template Method has several positive impacts on the code structure and performance. But, on the other hand, it can also make the processes tedious and have a few disadvantages. Let’s show you what they are.
Advantages of the Template Method
- No Code Duplication: This pattern reduces code duplication, making it perfect for class libraries. It factors out common behavior in libraries and optimizes their performance.
- Easy Handling and Higher Readability: To keep track of overriding, users can add a prefix to the names of the methods, for instance, DoRead, DoCreate, etc. This allows easier handling of codes with multiple methods.
- Flexibility: The Template Method provides basic definitions in the parent class. However, the subclasses determine how to implement the operations. Different subclasses can do the same task differently. Hence, there is flexibility in solving a problem, which comes in handy when the clients need customizations.
Disadvantages of the Template Method
- Too many Primitive Operations increase complexity: The goal of this design pattern is to limit the number of primitive operations. If there are too many operations that the subclass must override, the entire program becomes tedious to handle.
- Suppression of template: The entire algorithm malfunctions if the parent operations get suppressed by some overriding implementations.
- Stuck with a design: Since this pattern defines a specific design outline, the customers find themselves stuck on a particular design structure.
Patterns related to the Template Method design pattern
The Template Method has the following related patterns:
- Factory Method Pattern – factory methods are usually called inside a template method to implement subclasses.
- Strategy Pattern – this pattern relates to the template method as both deal with variations in algorithms. However, the Strategy Pattern uses delegation to vary the entire algorithm, whereas this pattern uses inheritance to change only specific parts of the algorithm.
What are the different types of methods a Template Method can call?
The template method can call various methods or operations to define and deter tasks to subclasses. These are:
- Concrete Operations – on concrete or client classes.
- Concrete Abstract Method – useful for the subclasses.
- Hook Operations – subclasses can use them for extensions.
- Primitive Operations – inside the abstract parent class.
- Factory Methods – for implementation of subclasses.
Conclusion
Design patterns reduce the effort of programmers by cutting down their work.
The Template Method is no different. With its ability to make code reusable, customizable and compact, programmers can extensively use it for framework designs. It follows the approach required intrinsically for creating frameworks. By deterring work to subclasses, the structural organization of the code remains clean and highly readable, and you can implement behavioral changes without having to recreate the entire design.
So, if you have created a solution you want to provide to your clients with little variations, refactor the algorithm with the Template Method to reduce your efforts and time consumption.
If you want to learn more about design patterns, check the separate in-depth article about design patterns in C#.