In this post, we will learn Template Method Pattern implementation with examples from Head First Design Patterns Book.
Table of contents
Table of contents
- Overview
- Class Diagram
- Implementation with Example
- Conclusion (Source code on Github Repository)
- References
1. Overview
Template Method Pattern defined
The Template Method Pattern defines the skeleton of an algorithm in an operation,
deferring some steps to subclasses. Template method lets subclasses redefine certain
steps of an algorithm without changing the algorithm's structure.
1.1 When to use template method pattern
- To implement the invariant parts of an algorithm once and leave it up to subclasses to implement the behavior that can vary.
- When common behavior among subclasses should be factored and localized in a common class to avoid code duplication. This is a good example of "refactoring to generalize" as described by Opdyke and Johnson. You first identify the differences in the existing code and then separate the differences into new operations. Finally, you replace the differing code with a template method that calls one of these new operations.
- To control subclasses extensions. You can define a template method that calls "hook" operations at specific points, thereby permitting extensions only at those points.
The Hollywood Principle
Don't call us, we will call you.
The connection between the Hollywood Principle and Template Method pattern is probably somewhat apparent: when we design with Template Method Pattern, we are telling subclasses, "don't call us, we'll call you."
This connection between the Hollywood Principle and Template Method pattern explained in the example.
2. Class Diagram
3. Implementation with Example
Let's implement Coffee Beverage example from Head First Design Patterns Book.
Coffee Beverage System provides two features :
-
StarBuzz Coffee Recipe
-
StarBuzz Tea Recipe
StarBuzz Coffee Recipe Let's start with the recipe.
1. Boil some water
2. Brew coffee in boiling water
3. Pour coffee in cup
4. Add sugar and milk
StarBuzz Tea Recipe Let's start with the recipe.
1. Boil some water
2. Steep tea in boiling water
3. Pour tea in cup
4. Add lemon
Notice that both recipes follow same algorithms:
Let's write template method prepareRecipe() method :
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
Follow the steps to implementation of a Template design pattern.
Let's create a coffee beverage system
Step 1: Create CaffeineBeverage class, which defines a skeleton for the algorithm.
StarBuzz Coffee Recipe
StarBuzz Tea Recipe
1. Boil some water
2. Brew coffee in boiling water
3. Pour coffee in cup
4. Add sugar and milk
1. Boil some water
2. Steep tea in boiling water
3. Pour tea in cup
4. Add lemon
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
public abstract class CaffeineBeverage {
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
abstract void brew();
abstract void addCondiments();
void boilWater() {
System.out.println("Boiling water");
}
void pourInCup() {
System.out.println("Pouring into cup");
}
}
Step 2: Create a Coffee class, which extends an abstract CaffeineBeverage class and implements abstract methods.
public class Coffee extends CaffeineBeverage {
public void brew() {
System.out.println("Dripping Coffee through filter");
}
public void addCondiments() {
System.out.println("Adding Sugar and Milk");
}
}
Step 3: Create a Tea class which extends an abstract CaffeineBeverage class and implements abstract methods.
public class Tea extends CaffeineBeverage {
public void brew() {
System.out.println("Steeping the tea");
}
public void addCondiments() {
System.out.println("Adding Lemon");
}
}
Step 4: With a hook, we can override a method or not, It's our choice, If we don't then abstract class provides a default implementation.
public abstract class CaffeineBeverageWithHook {
void prepareRecipe() {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
addCondiments();
}
}
abstract void brew();
abstract void addCondiments();
void boilWater() {
System.out.println("Boiling water");
}
void pourInCup() {
System.out.println("Pouring into cup");
}
boolean customerWantsCondiments() {
return true;
}
}
Step 5: Let's override the hook() method and provide the own implementation.
import java.io.*;
public class CoffeeWithHook extends CaffeineBeverageWithHook {
public void brew() {
System.out.println("Dripping Coffee through filter");
}
public void addCondiments() {
System.out.println("Adding Sugar and Milk");
}
public boolean customerWantsCondiments() {
String answer = getUserInput();
if (answer.toLowerCase().startsWith("y")) {
return true;
} else {
return false;
}
}
private String getUserInput() {
String answer = null;
System.out.print("Would you like milk and sugar with your coffee (y/n)? ");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
answer = in.readLine();
} catch (IOException ioe) {
System.err.println("IO error trying to read your answer");
}
if (answer == null) {
return "no";
}
return answer;
}
}
import java.io.*;
public class TeaWithHook extends CaffeineBeverageWithHook {
public void brew() {
System.out.println("Steeping the tea");
}
public void addCondiments() {
System.out.println("Adding Lemon");
}
public boolean customerWantsCondiments() {
String answer = getUserInput();
if (answer.toLowerCase().startsWith("y")) {
return true;
} else {
return false;
}
}
private String getUserInput() {
// get the user's response
String answer = null;
System.out.print("Would you like lemon with your tea (y/n)? ");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
answer = in.readLine();
} catch (IOException ioe) {
System.err.println("IO error trying to read your answer");
}
if (answer == null) {
return "no";
}
return answer;
}
}
Step 6: Test the above implementation.
Let's create a hot coffee and hot tea, here customer needs to decide whether he/she wants condiment by an input.
public class BeverageTestDrive {
public static void main(String[] args) {
Tea tea = new Tea();
Coffee coffee = new Coffee();
System.out.println("\nMaking tea...");
tea.prepareRecipe();
System.out.println("\nMaking coffee...");
coffee.prepareRecipe();
TeaWithHook teaHook = new TeaWithHook();
CoffeeWithHook coffeeHook = new CoffeeWithHook();
System.out.println("\nMaking tea...");
teaHook.prepareRecipe();
System.out.println("\nMaking coffee...");
coffeeHook.prepareRecipe();
}
}
Output :
Making tea...
Boiling water
Steeping the tea
Pouring into cup
Adding Lemon
Making coffee...
Boiling water
Dripping Coffee through filter
Pouring into cup
Adding Sugar and Milk
Making tea...
Boiling water
Steeping the tea
Pouring into cup
Would you like lemon with your tea (y/n)? y
Adding Lemon
Making coffee...
Boiling water
Dripping Coffee through filter
Pouring into cup
Would you like milk and sugar with your coffee (y/n)? y
Adding Sugar and Milk
4. Conclusion
In this post, we have learned the Template Method Pattern from Head First Design Patterns book. There is a separate post for Factory Pattern in detail with examples, advantages, real-world examples.
All the source code for this post available on Github Repo. This is an eclipse project so you can import into your workspace and play with it.
There more examples available on Github Repository
https://github.com/RameshMF/headfirst_design_patterns/tree/master/src/headfirst/templatemethod
https://github.com/RameshMF/headfirst_design_patterns/tree/master/src/headfirst/templatemethod
Read more about Factory Pattern on
https://ramesh-java-design-patterns.blogspot.com/2017/12/template-method-design-pattern.html
https://ramesh-java-design-patterns.blogspot.com/2017/12/template-method-design-pattern.html
5. Reference
https://ramesh-java-design-patterns.blogspot.com/2017/12/template-method-design-pattern.html
6. Top Java Tutorials
- Java Tutorial for Beginners
- 50 Java Keywords
- JDBC 4.2 Tutorial
- All Java/J2EE Tutorial
- Java 8 Tutorial
- Java Collections Tutorial
- Java Exceptions Tutorial
- Java Generics Tutorial
- Java 8 Stream API Tutorial
- Java Wrapper Classes
- Java Arrays Guide
- Java Multithreading Tutorial
- Java Concurrency Tutorial
- Oops Concepts Tutorial
- Java String API Guide
- Java Reflection API Tutorial
- Java I/O Tutorial
- Date and Time API Tutorial
- JUnit 5 Tutorial
- JUnit 4 Tutorial
- Java XML Tutorial
- Google GSON Tutorial
Comments
Post a Comment
Leave Comment