1, Concept
Template design pattern - based on abstract classes, the core of which is the encapsulation algorithm
Template method defines the steps of an algorithm and allows subclasses to provide concrete implementation for one or more steps. Template method patterns include Spring, Servlet, AQS, etc
Define the skeleton of an algorithm in a method, and delay some specific steps to subclasses. Template pattern enables subclasses to redefine some steps in the algorithm without changing the algorithm structure, so as to improve the code reusability.
advantage:
Using the template method pattern, while defining the algorithm skeleton, it can flexibly implement the specific algorithm to meet the flexible needs of users
Disadvantages:
If the algorithm skeleton is modified, the abstract class needs to be modified
Before we talk about the template design pattern, we use code to implement the classes made of coffee and tea:
Common class writing
public class MakeDrink { public static void main(String[] agrs) { Coffee coffee = new Coffee(); Tea tea = new Tea(); coffee.makeCoffee(); System.out.println("~~~~~~"); tea.makeTea(); } } class Coffee { //make coffee void makeCoffee() { boilWater(); brewCoffeeGrings(); pourInCup(); addSugarAndMilk(); } public void boilWater() { System.out.println("Boil the water"); } public void brewCoffeeGrings() { System.out.println("Brew coffee"); } public void pourInCup() { System.out.println("Pour the coffee into the cup"); } public void addSugarAndMilk() { System.out.println("Add sugar and milk"); } } class Tea { //make tea void makeTea() { boilWater(); steepTeaBag(); pourInCup(); addLemon(); } public void boilWater() { System.out.println("Boil the water"); } public void steepTeaBag() { System.out.println("Soak tea"); } public void pourInCup() { System.out.println("Pour the tea into the cup"); } public void addLemon() { System.out.println("Add lemon"); } }
We found duplicate code in coffee and Tea classes, so we need to reorganize our design.
Since tea and coffee are so similar, we should extract the common parts and put them into a base class. Start with the brewing method. Observing the brewing methods of coffee and tea, we will find that both brewing methods adopt the same algorithm:
-
- Boil the water
- Make a drink with hot water
- Pour the drink into the cup
- Add appropriate seasoning to the beverage
In fact, there is little difference between steeping and brewing. Therefore, we give it a new method name brew(), so that we can use this method no matter what kind of beverage we brew.
Similarly, adding sugar, milk or lemon is also very similar. They all add other spices to the beverage, so we also give it a common name addCondiments().
In addition, no matter making coffee or tea, they are actually making drinks. We change the name of the algorithm to making drinks
Template method design pattern
uml diagram
public class TemplateMethodPatternTest1 { /** * Template method abstract class */ abstract class DrinkProduction { /** * Steps for producing beverages * final Prohibit subclass override */ public final void makingDrinks() { boilWater(); brew(); pourInCup(); addCondiments(); } /** * Step 1: boil water */ public void boilWater() { System.out.println("Boil the water"); } /** * Step 2: add main material * Force subclass implementation */ public abstract void brew(); /** * Step 3: pour into the teacup */ public void pourInCup() { System.out.println("Pour into the cup"); } /** * Step 4: add seasoning * Force subclass implementation */ public abstract void addCondiments(); } class Coffee extends DrinkProduction { @Override public void addCondiments() { System.out.println("Add milk and sugar"); } @Override public void brew() { System.out.println("join coffee cook"); } } class Tea extends DrinkProduction { @Override public void addCondiments() { System.out.println("Add lemon"); } @Override public void brew() { System.out.println("Add tea and cook"); } } public void test(){ Coffee coffee = new Coffee(); coffee.makingDrinks(); System.out.println("~~~~~~"); Tea tea = new Tea(); tea.makingDrinks(); } public static void main(String[] args) { TemplateMethodPatternTest1 tem = new TemplateMethodPatternTest1(); tem.test(); } }
There is also a hook usage in template design mode
Hook methods are a kind of "default do nothing methods", and subclasses can decide whether to override them as appropriate.
For example, when making tea, the last step is not to add lemon
public class TemplateMethodPatternTest2 { /** * Template method abstract class */ abstract class DrinkProduction { /** * Steps for producing beverages * final Prohibit subclass override */ public final void makingDrinks() { boilWater(); brew(); pourInCup(); //The hook determines whether to call if(isAddCondiments()) { addCondiments(); } } /** * Step 1: boil water */ public void boilWater() { System.out.println("Boil the water"); } /** * Step 2: add main material */ public abstract void brew(); /** * Step 3: pour into the teacup */ public void pourInCup() { System.out.println("Pour into the cup"); } /** * Step 4: add seasoning */ public abstract void addCondiments(); /** * Hook writing * Override this method if not required * @return */ public boolean isAddCondiments(){ return true; } } class Coffee extends DrinkProduction { @Override public void brew() { System.out.println("join coffee Keep cooking"); } @Override public void addCondiments() { System.out.println("Add milk and sugar"); } } class Tea extends DrinkProduction { @Override public void brew() { System.out.println("Add tea and cook"); } // It doesn't need to be implemented, just send it by air @Override public void addCondiments() { } @Override public boolean isAddCondiments(){ return false; } } public void test(){ Coffee coffee = new Coffee(); coffee.makingDrinks(); System.out.println("~~~~~~"); Tea tea = new Tea(); tea.makingDrinks(); } public static void main(String[] args) { TemplateMethodPatternTest2 tem = new TemplateMethodPatternTest2(); tem.test(); } }