《Head First Design Patterns》:第8章,模板方法(Template Method)模式

模板方法的定义

模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。

场景

Starbuzz饮品店培训

场景描述

Starbuzz内部有两种饮料:咖啡和茶。需要对新加入的师傅进行饮品制作的培训,已知:a)咖啡和茶都有各自的冲泡方式,b)咖啡和茶的冲泡有相同和不同的步骤。如何才能简化培训时的步骤:难道一定要培训完一遍咖啡的制作过程,再培训一遍茶的制作过程吗?

Starbuzz咖啡冲泡法 Starbuzz茶冲泡法
1.把水煮沸;
2.用沸水冲泡咖啡;
3.把咖啡倒进杯子;
4.加糖和牛奶;
1.把水煮沸;
2.用沸水浸泡茶叶;
3.把茶倒进杯子;
4.加柠檬;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 addLemon() {
System.out.println("Adding Lemon");
}
public void pourInCup() {
System.out.println("Pouring into cup");
}
}

方案

注意这两种冲泡法都采用了相同的算法:

  1. 把水煮沸;
  2. 用热水泡咖啡或茶;
  3. 把饮料倒进杯子;
  4. 在饮料内加入适当调料;

prepareRecipe()方法进行如下抽象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Tea extends CaffeineBeverage {
public void brew() {
System.out.println("Steeping the tea");
}
public void addCondiments() {
System.out.println("Adding Lemon");
}
}

public class Coffee extends CaffeineBeverage {
public void brew() {
System.out.println("Dripping Coffee through filter");
}
public void addCondiments() {
System.out.println("Adding Sugar and Milk");
}
}

以上抽象类CaffeineBeverage中的prepareRecipe()方法就是模版方法

  1. 首先,它是一个方法;
  2. 它用作一个算法的模板,定义了算法的步骤,在这个例子中,算法就是制作咖啡因饮料;算法内每一个步骤都被一个方法代表了,例如boilWater()brew()pourInCup()addCondiments()
  3. 算法内的一些方法在超类中处理,一些方法则是在子类中处理;

模板方法模式VS策略模式

模板方法模式 策略模式
定义 定义一个算法大纲,由子类定义其中算法的某些步骤 封装可互换的行为,使用委托来决定要采用哪一个行为
实现 通过继承 通过对象组合