The next design pattern is the Template Method Design Pattern, which is also one of the Behavioral Design Pattern. Let's take a look at the definition of this design pattern and how to implement it in C# and .Net.
Note: Code can be downloaded at my Github.
1. What is the Template Method Design Pattern?
Template Method is a behavioral design pattern that defines the skeleton of an algorithm in the superclass but lets subclasses override specific steps of the algorithm without changing its structure.
The template method is a method in a superclass, usually an abstract superclass, and defines the skeleton of an operation in terms of a number of high-level steps. These steps are themselves implemented by additional helper methods in the same class as the template method.
2. When to implement the Template Method Design Pattern?
The Template Method Design Pattern can be implemented when:
- you want to let clients extend only particular steps of an algorithm, but not the whole algorithm or its structure.
- you have several classes that contain almost identical algorithms with some minor differences. As a result, you might need to modify all classes when the algorithm changes.
3. How to implement the Template Method Design Pattern?
Below is how to implement the Template Method Design Pattern in C# and .Net:
Step 1: Create an Abstract class
The Abstract Class defines a template method that contains a skeleton of some algorithm, composed of calls to(usually) abstract primitive operations.
Concrete subclasses should implement these operations, but leave the template method itself intact.
abstract class AbstractClass { // The template method defines the skeleton of an algorithm. public void TemplateMethod() { this.BaseOperation1(); this.RequiredOperations1(); this.BaseOperation2(); this.Hook1(); this.RequiredOperation2(); this.BaseOperation3(); this.Hook2(); } // These operations already have implementations. protected void BaseOperation1() { Console.WriteLine("AbstractClass says: I am doing the bulk of the work"); } protected void BaseOperation2() { Console.WriteLine("AbstractClass says: But I let subclasses override some operations"); } protected void BaseOperation3() { Console.WriteLine("AbstractClass says: But I am doing the bulk of the work anyway"); } // These operations have to be implemented in subclasses. protected abstract void RequiredOperations1(); protected abstract void RequiredOperation2(); // These are "hooks." Subclasses may override them, but it's not // mandatory since the hooks already have default (but empty) // implementation. Hooks provide additional extension points in some // crucial places of the algorithm. protected virtual void Hook1() { } protected virtual void Hook2() { } }
Step 2: Create a Concrete classes
Concrete classes have to implement all abstract operations of the base class. they can also override some operations with a default implementation.
class ConcreteClass1 : AbstractClass { protected override void RequiredOperations1() { Console.WriteLine("ConcreteClass1 says: Implemented Operation1"); } protected override void RequiredOperation2() { Console.WriteLine("ConcreteClass1 says: Implemented Operation2"); } } class ConcreteClass2 : AbstractClass { protected override void RequiredOperations1() { Console.WriteLine("ConcreteClass2 says: Implemented Operation1"); } protected override void RequiredOperation2() { Console.WriteLine("ConcreteClass2 says: Implemented Operation2"); } protected override void Hook1() { Console.WriteLine("ConcreteClass2 says: Overridden Hook1"); } }
Step 3: Define the client code
class Client { // The client code calls the template method to execute the algorithm. // Client code does not have to know the concrete class of an object it // works with, as long as it works with objects through the interface of // their base class. public static void ClientCode(AbstractClass abstractClass) { // ... abstractClass.TemplateMethod(); // ... } }
Done! You can now implement these above on client side:
class Program { static void Main(string[] args) { Console.WriteLine("Same client code can work with different subclasses:"); Client.ClientCode(new ConcreteClass1()); Console.Write("\n"); Console.WriteLine("Same client code can work with different subclasses:"); Client.ClientCode(new ConcreteClass2()); } }
Output:
4. Conclusion
I hope this article is helpful. Please let me know your thoughts by commenting in the section below.