模板方法模式

说明

模板方法模式

  • 定义
    在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使的子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。将主要的方法定义为final,防止子类修改算法骨架,将子类必须实现的方法定义为abstract。而普通的方法(无final或abstract修饰)则称之为钩子。
  • 钩子作用
    1. 作为可选内容,子类可以重写或者置之不理
    2. 让子类有机会对模板方法中即将发生的或者已经发生的步骤做出反应
    3. 作为控制条件,使得子类可以影响到抽象类中的算法流程
  • 角色
    1. 模板抽象父类
    2. 模板子类
  • 优点
    1. 模板方法模式在一个类中形式化地定义算法,而由它的子类实现细节的处理。
    2. 模板方法是一种代码复用的基本技术。它们在类库中尤为重要,它们提取了类库中的公共行为。
    3. 模板方法模式导致一种反向的控制结构,这种结构有时被称为“好莱坞法则” ,即“别找我们,,我们找你”通过一个父类调用其子类的操作(而不是相反的子类调用父类),通过对子类的扩展增加新的行为,符合“开闭原则”
  • 缺点
    每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,但是更加符合“单一职责原则”,使得类的内聚性得以提高。
  • 总结
    1. 模板方法模式是一种类的行为型模式,在它的结构图中只有类之间的继承关系,没有对象关联关系。
    2. 板方法模式是基于继承的代码复用基本技术,模板方法模式的结构和用法也是面向对象设计的核心之一。在模板方法模式中,可以将相同的代码放在父类中,而将不同的方法实现放在不同的子类中。
    3. 在模板方法模式中,我们需要准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来让子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现,这就是模板方法模式的用意。模板方法模式体现了面向对象的诸多重要思想,是一种使用频率较高的模式。

代码示例

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/**
* 模板方法中的父类,prepare方法定义了算法步骤,不同的饮料需要实现不同的brew,并可以选择是否覆盖food方法
*
* @author sky
*
*/
public abstract class Beverage {

/**
* 准备饮料的过程,烧水,冲泡,倒杯,搭配糕点
*/
final public void prepare() {
boilWater();
brew();
pourInCup();
food();
}

final public void boilWater() {
System.out.println("烧水");
}

abstract void brew();

final public void pourInCup() {
System.out.println("将饮料倒入杯子里");
}

public void food() {
System.out.println("搭配一点糕点");
}

}

/**
* 咖啡,实现了brew方法
*
* @author sky
*
*/
public class Coffee extends Beverage {

@Override
void brew() {
System.out.println("冲咖啡");
}

}

/**
* 茶,实现了brew方法,重写了food方法
*
* @author sky
*
*/
public class Tea extends Beverage {

@Override
public void food() {
System.out.println("喝茶不需要搭配糕点");
}

@Override
void brew() {
System.out.println("冲茶");
}

}

/**
* 测试类
*
* @author sky
*
*/
public class Test {

public static void main(String[] args) {
System.out.println("---茶---");
Beverage tea = new Tea();
tea.prepare();
System.out.println("---咖啡---");
Beverage coffee = new Coffee();
coffee.prepare();
}

}

输出

1
2
3
4
5
6
7
8
9
10
---茶---
烧水
冲茶
将饮料倒入杯子里
喝茶不需要搭配糕点
---咖啡---
烧水
冲咖啡
将饮料倒入杯子里
搭配一点糕点