设计模式笔记 - 模板模式(Template Pattern)

模式定义

模板模式(Template Pattern)定义一个操作中算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构,重新定义算法中的某些特定步骤。


模式结构

模板模式包含以下角色:

  • AbstractClass:抽象类
  • ConcreteClass:具体类

img


模式实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/*
* 此例为实现模板模式的小例子。茶与咖啡同属于咖啡因的种类,两者的冲泡方式也十分相同:煮沸水、添
* 加咖啡豆(或茶包)、导入杯中、添加调料。利用模板模式,可以将两者的冲泡过程进行抽象泛化。
*/
// AbstractClass - 抽象类
public abstract class CaffeineBeverage {
// final - 标记子类无法重载该方法
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
hook();
addCondiments();
}

// 指定子类必须实现以下两个抽象方法
abstract void brew();

abstract void addCondiments();

void boilWater() {
System.out.println("Boiling Water!");
}

void pourInCup() {
System.out.println("Pouring into Cup!");
}

// hook钩子 - 空方法 - 使算法更具拓展性
void hook() {
;
}
}

// ConcreteClass - 具体类
// 茶
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!");
}

public void hook() {
System.out.println("Please give me a spoon!");
}
}

public class Test {
public static void main(String[] args) {
CaffeineBeverage tea = new Tea();
CaffeineBeverage coffee = new Coffee();

tea.prepareRecipe();
coffee.prepareRecipe();
}
}

模式分析

  • 通常来说,模板模式中抽象类负责实现模板方法,定义算法的骨架,而具体类实现抽象类中的抽象方法,实现完整的算法。

模板模式的优点:

  • 模板模式提供了抽象类专注于算法本身,并定义了算法的大致骨架,使代码的复用最大化。
  • 子类可以继承模板类,并实现算法所指定的细节,有助于算法的扩展。

模板模式的缺点:

  • 抽象类内部的细节若划分太过于细节,将减少子类实现该抽象类的弹性,不易于扩展。

模式扩展

模板模式中不一定非要继承抽象类才能够实现算法的复用。java.util 包中 Array.sort() 静态方法为我们提供了排序的模板,但是我们并不能够继承数组类,所以它要求需要排序的类实现Comparable接口,才能够正常使用该排序。


Q&A

  • 当我创建一个模板方法时,怎么知道什么时候才能使用抽象方法,什么时候用钩子当你的子类“必须”提供算法中某个方法或步骤的实现时,就使用抽象方法。如果算法的这个部分是可选的,就使用钩子。
  • 使用钩子的真正目的钩子可以让子类实现算法中可选的部分,换种角度来说,在钩子对于子类的实现并不重要的时候,子类可以对此置之不理。钩子的另外一个用法,是让子类能够有机会对模板方法中某些即将发生的(或刚刚发生的)步骤做出反应。
  • 策略模式与模板模式的区别策略模式与模板模式的思想是封装算法。但策略模式的侧重点在于使用组合,实现算法的替换,而模板模式的侧重点使用继承,实现算法框架的某些细节。