意图:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
结构:
其中AbstractClass 实现为:
public abstract class AbstractClass {
final void templateMethod(){
primitiveOperation1();
primitiveOperation2();
concreteOperation();
hook();//钩子
}
abstract void primitiveOperation1();
abstract void primitiveOperation2();
final void concreteOperation(){
//这里是实现
}
void hook(){
}
}
先看我们一个例子,我们要进行泡茶和泡咖啡,我们会如何进行操作:
咖啡:
1.把水煮沸
2.用沸水冲泡咖啡粉
3.把咖啡倒进杯子
4.加糖和咖啡
public class Coffee {
void prepareRecipe(){
boilWater();
brewCoffeeGrinds();
pourInCup();
addSugarAndMilk();
}
public void boilWater(){
System.out.println("Boiling Water");
}
public void brewCoffeeGrinds(){
System.out.println("Dripping Coffee through filter");
}
public void pourInCup(){
System.out.println("Pouring into cup");
}
public void addSugarAndMilk(){
System.out.println("Adding Sugar and Milk");
}
}
茶:
1.把水煮沸
2.用沸水浸泡茶叶
3.把茶倒进杯子
4.加柠檬
public class Tea {
void prepareRecipe(){
boilWater();
steepTeaBag();
pourInCup();
addLemon();
}
public void boilWater(){
System.out.println("Boiling Water");
}
public void steepTeaBag(){
System.out.println("Steeping the tea");
}
public void pourInCup(){
System.out.println("Pouring into cup");
}
public void addLemon(){
System.out.println("Adding Lemon");
}
}
我们会发现其实有相同的方法,我们将其抽象化,其实我们发现咖啡的brewCoffeeGrinds()和茶的steepTeaBag()其实都是泡的动作,然后在发现咖啡的addSugarAndMilk()和茶的addLemon()都是加原料的动作,我们可以将这两个动作brew()和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");
}
}
brew()方法和addCondiments()方法由子类方法延迟实现。
上面有一个hook()方法,我们到底何时使用钩子这个方法呢?就是一些步骤进行可以选择的时候。
下面我们将介绍模板方法和策略模式的一些不同点:
1.模板方法使用的继承模式,策略模式使用的是对象组合模式。
2.模板方法依赖度比策略高。
总结:
1.为防止子类修改模板方法的算法,可以将模板方法声明为final.
2.其中模板方法模式运用了好莱坞原则。
3.策略模式和模板方法模式都封装了算法,但是模板方法模式使用继承,而策略模式使用对象组合模式。
4.其实工厂方法是一种特殊的模板方法的版本。