设计模式 -(19)模板方法模式(Template Method Pattern)
前言
举一些生活中的例子:
- 去银行办理业务会经历以下步骤:1.取号、2.排队、3.办理具体业务、4.给服务评分,其中在第三步中有的人办理存款,有的人办理取款,有的人办理贷款,在这个步骤中不同的人处理的事情不一样,而除了这个步骤以外其他步骤都一样
- 做菜时一般都经历 去皮, 洗菜,切菜,烹饪等步骤,其中去皮,洗菜,切菜操作大同小异,而烹饪时则需要根据不同菜品调整不同的烹饪方式,如鱼可以清蒸,肉可以小炒,骨头用来炖汤
以上举的例子中,大部分操作固定只有一小部分操作需要根据业务调整处理方式的案例就可以使用模板方法模式
举例
以做菜举例:
在 Cook 类中,将做菜分为了四个步骤,去皮,洗菜,切菜,烹饪,这些步骤都通过 make 方法调用,不管做什么菜都调用 make 方法即可
public abstract class Cook {
protected void removePeel() {
System.out.println("去皮");
}
protected void wash() {
System.out.println("洗菜");
}
protected void cutUp() {
System.out.println("切菜");
}
/**
* 烹饪,不同菜烹饪方式不一样
*/
abstract void cooking();
public void make(){
removePeel();
wash();
cutUp();
cooking();
}
}
烹饪清蒸鱼:
public class CookingFish extends Cook{
@Override
void cooking() {
System.out.println("清蒸");
}
public static void main(String[] args) {
Cook cookingFish = new CookingFish();
cookingFish.make();
}
}
去皮
洗菜
切菜
清蒸
烹饪土豆:
public class CookingPotato extends Cook{
@Override
void cooking() {
System.out.println("炒着吃");
}
public static void main(String[] args) {
Cook cookingPotato = new CookingPotato();
cookingPotato.make();
}
}
去皮
洗菜
切菜
炒着吃
使用钩子函数
在上面的例子中,不是烹饪所有的菜都需要去皮,比如青菜,这个时候在模板方法 make 中,removePeel 去皮操作需要根据不同菜品来判断是否调用,这个时候可以在 Cook 类中定义一个是否去皮的方法,比如 needRemovePeel(),这个方法默认返回 true (表示需要去皮),子类可以重写 needRemovePeel 方法,返回 false 则可以控制主类不去皮,像 needRemovePeel 这种有默认实现,并且子类通过覆盖可以改变父类行为的方法称为钩子方法
具体实现:
public abstract class Cook2 {
protected void removePeel() {
System.out.println("去皮");
}
protected void wash() {
System.out.println("洗菜");
}
protected void cutUp() {
System.out.println("切菜");
}
protected boolean needRemovePeel() {
return true;
}
/**
* 烹饪,不同菜烹饪方式不一样
*/
abstract void cooking();
public void make() {
if (needRemovePeel()) {
removePeel();
}
wash();
cutUp();
cooking();
}
}
白灼青菜:
如下所示,青菜不用去皮,所以重写 needRemovePeel 方法返回 false,在父类 Cook2 make 方法中 removePeel 去皮方法便不再调用
public class CookingVegetables extends Cook2{
@Override
public boolean needRemovePeel() {
return false;
}
@Override
void cooking() {
System.out.println("白灼青菜");
}
public static void main(String[] args) {
Cook2 cookingVegetables = new CookingVegetables();
cookingVegetables.make();
}
}
洗菜
切菜
白灼青菜