Template pattern is a behavioral pattern that allows part of an algorithm to vary independent of the rest of the algorithm. In other words, the bulk of the algorithm logic is defined in a base class (could be abstract) and the part that can change is defined in a derived class. Each derived class can then define its own logic for the changing part. Use the template pattern when you have multiple algorithms that have mostly common logic but have minor differences. The minor differences are extracted out of the base class and into its own derived class.
To illustrate the template pattern we use the example of a car manufacturing algorithm.
We define a base class That builds the car. It has the following methods (in that order)- buildChasis(), buildEngine(), buildBody(),addFeatures(). The first three methods are defined in the base class itself since they are same for all variants. The last part of the algorithm – addFeatures() is declared abstract and the subclasses provide the implementation for it.
The Car Manufacturing algorithm. The buildCar method specifies the algorithm that has various parts to it. This class provides logic for all the parts except for addFeatures which is declared abstract. This is the template method.
public abstract class CarManufacturingAlgorithm { public void buildCar() { buildChasis(); buildEngine(); buildBody(); addFeatures(); } private void buildChasis() { // build chasis } private void buildEngine() { // build engine } private void buildBody() { // buildbody } abstract void addFeatures(); }
This is the first variant that adds the features to the base algorithm.
public class CarManufacturingAlgorithmVariant1 extends CarManufacturingAlgorithm { @Override void addFeatures() { // add features for variant 1 } }
The example above showed template method in action. We defined an algorithm called CarManufacturingAlgorith that had all the steps except one step which we let the derived class define.
There is another flavor to the template pattern. Lets say that in the base class (CarManufacturingAlgorithm) We want to add some features that are common to all the cars but add some advanced features in the derived class. In that case, we can provide some basic implementation of addFeatures in the base class and then let the subclass add more features to it. We are now free to declare the base class non abstract. However, there is one difference that marks this approach different from simple overriding. We provide a hook in the base class where the derived class can inject its logic. Normally when a derived class overrides a method, it would need to use super to first let the base class perform its operation. With the hook concept the control stays with the base class and it then calls the hook method which the derived class implements. Lets modify the above example to use a hook.
We have changed the base algorithm to allow add features to add basic features. It then allows the derived class to ‘hook’ into the algorithm by providing an implementation of addAdvancedFeatures.
public class CarManufacturingAlgorithmWithHooks { public void buildCar() { } public void buildChasis() { // build chasis } public void buildEngine() { // build engine } public void buildBody() { // buildbody } public void addFeatures() { // add basic features addAdvancedFeatures(); } // this is the hook. Subclasses do not have remember to call parents method // to add the basic features. public void addAdvancedFeatures() { }
public class CarManufacturingAlgorithmVariant1 extends CarManufacturingAlgorithm { @Override void addFeatures() { // add features for variant 1 } }
Here’s the class diagram :
This finishes our discussion on the template pattern.