The Template Method Pattern defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
You can use this pattern when you recognize that two or more algorithms are similar except that some of the steps require different implementations.
General procedure to follow:
- Create a class (abstract if you want mandatory steps)
- Create a generalized version of the algorithm in a method or more (possibly sealed)
- Use protected abstract methods when a step of the algorithm is required
- Use protected virtual methods when a step is optional
- If needed, add a default implementation for optional steps
- Create a subclass for each specific algorithm implementing all the various steps
It is quite easy to create a simple example of the pattern but I think that is much more useful to identify implementation of the pattern in your favourite frameworks. This pattern is used in almost every framework.
Example: The XNA Framework
The XNA Framework extensively use the Template Method Pattern to provide a base class Game that encapsulates the common algorithms of a game. Each subclass of the Game class implement a specific game reusing lots of the code defined in the baseclass.
If you look at the documentation of the Game class on MSDN you can see that there a lot of protected virtual methods. Each of this method can be seen as a step of the "generic game" algorithm.
Let's consider the two more important hooks:
Using a .NET Disassembler you can easily look inside the Game class and identify the template methods.
You can see that the Game class provides a default implementation of Update() and Draw() methods.
As a consumer of the framework the only thing you need to do is to override Update() and Draw() and the base class will take care of all the aspects of the game.
Example: Event Handling in .NET libraries
The entire .NET framework uses the Template Method Pattern extensively to provide internal clients with a simplified way to handle events.
Microsoft recommends using a protected virtual method for raising each event. This provides a way for subclasses to handle the event using an override.
You can see an example of this pattern in the ASP.NET Control class.
An internal client can override the method and add custom logic to it. Note that the Page class inherit indirectly from the Control class.
Having a default implementation makes the client asking the following questions:
- Should I call the base method?
- Should I write my custom code before calling the base method?
- Should I write my custom code after calling the base method?
There is not a generic answer to this questions because it always depends by the framework and how the base method is implemented. This should clearly be documented because it can be the source of many problems.
A way to avoid all of this problems is to use abstract methods. However, adding too many abstract methods can make the framework difficult to use because the client is forced to override all the methods even if it is not necessary.
Finding the right trade-off is surely not something easy to do.
Microsoft says on this:
The derived class can choose not to call the base class during the processing of OnEventName. Be prepared for this by not including any processing in the OnEventName method that is required for the base class to work correctly.
This problem is strictly related to the Liskov substitution principle. Not calling the base class can violate the principle.
Design Principles and Limitations
Design Principles and Limitations
It is possible to continue forever with examples from the .NET Framework but I think that you got the idea behind the pattern.
The object oriented design principles used by the pattern are:
- "The Hollywood Principle": Don't call us, we'll call you.
- The Open/Close principle
The main benefits of the pattern is:
- Code reuse (subclasses implement only the behaviour that can vary)
There are however some limitations in using this pattern.
The first limitation is that the pattern rely on inheritance. A way to avoid inheritance and achieve a similar goal is to use the Strategy Pattern.
The second limitation is that inheritance makes difficult to merge two child algorithms into one. In that situation, the Decorator Pattern can be a solution.