什么是模板方法模式
在一个方法中定义一个算法的骨架,而把一些步骤延迟到子类。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。
这些算法步骤中的一个或者多个被定义为抽象的,由子类实现。
类图
代码
书中用泡茶和泡咖啡作为例子,比较了他们的共同点与不同点,从而做抽象。
泡咖啡的步骤:
- 把水煮沸
- 用沸水冲泡咖啡
- 把咖啡倒进杯子
- 加糖和奶
泡茶的步骤:
- 把水煮沸
- 用沸水浸泡茶叶
- 把茶倒进杯子
- 加柠檬
从上面可以看出,泡咖啡和泡茶的基本流程是一样的,而且其中把水煮沸的动作也是一样的
由上面的分析可以抽象出,代码如下
顶层抽象类的设计
public abstract class Beverage {
final void prepareRecipe() { //冲泡方法,定义为final,防止子类更改顺序
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 customerWantsConditions() { // 钩子函数
return true; //默认是添加的,子类可以覆盖这个方法
}
}
Tea
public class Tea extends Beverage {
@Override
void brew() {
System.out.println("Steeping the tea");
}
@Override
void addCondiments() {
System.out.println("Adding Lemon");
}
}
Coffee
public class Cofffee extends Beverage {
@Override
void brew() {
System.out.println("Coffee filter");
}
@Override
void addCondiments() {
System.out.println("adding sugar and milk");
}
}
应用
java API中很多地方会用到模板方法的思想,但使用形式不是完全跟书上类似
下面是一个Arrays.sort()的使用
鸭子类
public class Duck implements Comparable<Duck>{
private String name;
private int weight;
public Duck(String name, int weight) {
this.name = name;
this.weight = weight;
}
@Override
public String toString() {
return name + " " + weight;
}
@Override
public int compareTo(Duck other) {
return Integer.compare(this.weight, other.weight);
}
对鸭子进行排序
public class DuckStoreTest {
public static void main(String[] args) {
Duck[] ducks = {
new Duck("a", 5),
new Duck("b", 9),
new Duck("c", 3)
};
System.out.println("Before sort");
display(ducks);
Arrays.sort(ducks);
System.out.println("After sort");
Arrays.sort(ducks);
display(ducks);
}
public static void display(Duck[] ducks) {
for (Duck d : ducks) {
System.out.println(d);
}
}
}
Arrays.sort()是一个静态方法,这里用户类Duck实现了Comparable的方法,但是并不是通过继承父类的方式类实现。
设计原则
好莱坞原则:不要打电话给我们,我们会打电话给你们。强调了是高层组件去调用低层组件,低层子组件会参与计算,但是不直接调用高层组件。
优点
模板方法定义了算法的步骤,然后把这些步骤的实现延迟到了子类
提供了一种代码复用的重要技巧
工厂方法是模板方法的一个特例
策略模式和模板方法模式都是封装算法,但是前者是通过组合,而后者是通过继承。