What Is The Template Method Design Pattern?
There are still elements about this design method I am unsure of, so please feel free to leave feedback.
In software engineering, the template method pattern is a behavioural design pattern that defines the program skeleton of an algorithm in an operation, deferring some steps to subclasses. It lets one redefine certain steps of an algorithm without changing the algorithmβs structure. Wikipedia
And in case you were wondering what a behavioural design pattern is:
Behavioural design patterns are design patterns that identify common communication patterns among objects and realise these patterns. By doing so, these patterns increase flexibility in carrying out this communication. Wikipedia
My understanding is within an abstract class (base class), the template method outlines the steps of an algorithm as a concrete method.
Within the method, it calls abstract (primitive operations) and concrete methods (concrete operations) in the class, in a particular order.
The concrete methods called within a template method represents the parts of the algorithm which are standard. On the other hand, the abstract methods called represents the customisable aspects. A template method can also consist of abstract methods only.
Concrete classes, which extend from the base class, need to implement the abstract methods. As a result, this provides some customisation across the subclasses.
The abstract class can also contain hook methods, which the subclasses can override. Hook methods are explained in more detail further on in this blog post.
One of the purposes of the template method design pattern is to avoid code duplication. When implementing the pattern, the number of abstract methods to implement should be kept to a minimum.
Implementing The Template Design Pattern
Below is an example, demonstrating the use of the template design pattern. It consist of a base class called Greeter and the subclasses EnglishGreeter
and FrenchGreeter
.
The Greeter Class
Greeter is an abstract class. It contains a concrete method called greeting()
. This is the template method.
It also contains two abstract methods, doHello()
and doGoodbye()
. Subclasses of Greeter should implement the abstract methods.
1public abstract class Greeter {2 public final void greeting() {3 doHello();4 doGoodbye();5 }67 public abstract void doHello();89 public abstract void doGoodbye();10}
The EnglishGreeter Class
This class is a subclass of Greeter
. It implements the abstract methods doHello()
and doGoodbye()
.
1public class EnglishGreeter extends Greeter {2 @Override3 public void doHello() {4 System.out.println("Hello!");5 }67 @Override8 public void doGoodbye() {9 System.out.println("Goodbye!");10 }11}
The FrenchGreeter Class
This class is also a subclass of Greeter
and implements the abstract methods.
1public class FrenchGreeter extends Greeter {2 @Override3 public void doHello() {4 System.out.println("Bonjour!");5 }67 @Override8 public void doGoodbye() {9 System.out.println("Au revoir!");10 }11}
EnglishGreeter
and FrenchGreeter
have also inherited the greeting()
method from Greeter
.
Creating an instance of EnglishGreeter
and calling the greeting()
method, prints the following to the console:
1Hello!2Goodbye!
Creating an instance of FrenchGreeter and calling the greeting() method, prints the following to the console:
1Bonjour!2Au revoir!
Although doHello()
and doGoodbye()
are called in a particular order, the method bodies contain different content in EnglishGreeter
and FrenchGreeter
, resulting in different output.
Here is a UML diagram, outlining the Greeter
example:
The Template Method with Concrete Methods
Letβs change Greeter to include the concrete methods, waveHello()
and waveGoodbye()
. Both methods prints an emoji. Greeting()
is amended to call the new methods.
1public abstract class Greeter {2 public final void greeting() {3 waveHello();4 doHello();5 waveGoodbye();6 doGoodbye();7 }89 public void waveHello() {10 System.out.println("π");11 }1213 public abstract void doHello();1415 public void waveGoodbye() {16 System.out.println("ποΈ");17 }1819 public abstract void doGoodbye();20}
As the new methods are concrete, EnglishGreeter
and FrenchGreeter
do not need to implement them.
Creating an instance of EnglishGreeter
and calling the greeting()
method, prints the following to the console:
1π2Hello!3ποΈ4Goodbye!
Creating an instance of FrenchGreeter and calling the greeting() method, prints the following to the console:
1π2Bonjour!3ποΈ4Au revoir!
The emojis are consistent throughout both classes, and the variation of text outputted still remains. Here is a UML diagram, outlining this example:
Adding Hook Methods
A hook method can be defined as an optional method in the base class. It provides default behaviour, which subclasses can extend, if necessary. It is usually empty and does nothing by default.
For example, the Greeter
class now has an optional method, called celebrate
, which is empty.
1public abstract class Greeter {2 public final void greeting() {3 waveHello();4 doHello();5 celebrate();6 waveGoodbye();7 doGoodbye();8 }910 public void waveHello() {11 System.out.println("π");12 }1314 public abstract void doHello();1516 public void celebrate() {}1718 public void waveGoodbye() {19 System.out.println("ποΈ");20 }2122 public abstract void doGoodbye();23}
In the subclasses, celebrate()
can be overridden to edit the method. In the example below, EnglishGreeter
is overriding the celebrate method to print out "WOO HOO!"
1public class EnglishGreeter extends Greeter {2 @Override3 public void doHello() {4 System.out.println("Hello!");5 }67 @Override8 public void celebrate() {9 System.out.println("WOO HOO!");10 }1112 @Override13 public void doGoodbye() {14 System.out.println("Goodbye!");15 }16}
Creating an instance of EnglishGreeter
and calling the greeting()
method, prints the following to the console:
1π2Hello!3WOO HOO!4ποΈ5Goodbye!
The celebrate
method has not been overridden in the FrenchGreeter
subclass. As a result, there are no changes to what is printed when calling FrenchGreeter
's greeting method.
1π2Bonjour!3ποΈ4Au revoir!
Here is a UML diagram, outlining the example above:
Discussion