本章源码基于JDK1.7
模板方法模式的主要设计思想是定义一个算法框架,允许用子类重写或者其它方式对算法框架内的某个步骤的具体实现进行修改。
本章内容已冲泡咖啡和茶作为例子讲解,咖啡和茶叶作为饮料的一种有共通之处,首先烧水、然后冲泡咖啡或茶叶,最后将冲泡后的咖啡或茶叶水倒进杯子中。
我们可以将烧水行为和将饮料倒进杯子行为抽象出来,但是冲泡咖啡还是茶叶的话就必须要具体的去处理。
下面为具体代码实现
Drink.java
抽象父类Drink,其中boilWater和pourInCup是抽象出来的父类方法,由子类继承,brew冲泡方法则根据冲泡咖啡还是茶叶具体由子类去决定。
Drink中的prepareRecipe是算法主干方法,它决定了准备饮料步骤的算法逻辑,第一步烧水、第二步冲泡、第三步将饮料倒进杯子。
在Drink中同时也实现了一个钩子方法hook,该钩子方法能够影响到算法主干方法,子类方法通过重写该钩子方法来改变算法主干方法。
public abstract class Drink {
//准备饮料
void prepareRecipe(){
boilWater();
brew();
if(hook()){
pourInCup();
}
}
//烧水
public void boilWater(){
System.out.println("烧水");
}
//冲泡
public abstract void brew();
//将饮料倒进杯子里
public void pourInCup(){
System.out.println("倒饮料进杯子");
}
//钩子方法
public boolean hook(){
return true;
}
}
Tea.java
茶叶类重写饮料父类Drink的brew方法,实现冲泡茶叶的逻辑,并且重写hook方法,改变了父类的算法主干,冲泡完茶叶后并不将茶水倒入杯子中。
public class Tea extends Drink{
@Override
public void brew() {
System.out.println("冲泡茶叶");
}
//重写父类Drink的钩子方法,改变父类算法主干逻辑
@Override
public boolean hook() {
return false;
}
}
Coffee.java
咖啡类继承饮料父类Drink,重写brew方法实现冲泡咖啡的具体逻辑
public class Coffee extends Drink{
@Override
public void brew() {
System.out.println("冲泡咖啡");
}
}
Test.java
分别实例化茶叶和咖啡,分别准备两种饮料
public class Test {
public static void main(String[] args) {
Drink tea = new Tea();
tea.prepareRecipe();
System.out.println();
Drink coffee = new Coffee();
coffee.prepareRecipe();
}
}
运行结果
可以看到冲泡茶叶后并没有倒进杯子中,而咖啡冲泡后会倒入杯子中,说明钩子方法生效了,改变了主干算法逻辑。
延伸扩展
jdk源码中比较器其实也是一种模板方法模式,它的设计思想是定义一个算法主干,然后通过传入比较器或者实现实体的比较方法来对算法主干的某个步骤进行具体实现。