设计模式:模板方法模式

模板方法模式

提出问题

当多个类当中存在共同或相似的算法,因此有一些重复的代码块(方法)时,因此在这些类当中就有着重复的代码。

希望定义一个操作中的算法骨架,而将一些步骤延迟到子类中。

基础概述

是什么

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

模板方法

骨架prepareRecipe(),步骤即是算法内部的方法。

步骤延迟到子类中,即内部的一些抽象方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public abstract class CaffeineBeverage{
//prepareRecipe()是一个模板方法
//是用来制作咖啡因饮料的算法
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addConiments();
}

void boilWater() {
}

abstract void brew();

void pourInCup() {
}

abstract void addConiments();
}

模板方法原因:

  • 是一个方法
  • 用做一个算法的模板,在模板当中,算法的每一个步骤都被一个方法代表了。

一些方法由超类处理,即这个类,例如boilWater()

而另一些方法由子类处理,这些方法加上abstract标识,如addConiments()

分类

应用

适用性

  • 封装算法块,使得子类可以在任何时候都可以将自己挂接进运算里。

  • 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。

  • 各子类中的公共的行为应该被提取出来并集中到一个父类中以避免代码重复。

  • 控制子类扩展,模板方法只在特定点调用“hook”操作,这样就只允许在这些点进行扩展。

案例1

协作

结构

UML类图

1559632429677

参与者

  • AbstractClass。抽象类,定义抽象的原语操作,具体的子类将重定义它们以实现一个算法的各步骤。
    • 实现一个模板方法,定义一个算法的骨架,该模板方法不仅调用原语操作,也调用定义在AbstractClass或其他对象中的操作。
  • ConcreteClass。具体类,实现原语操作以完成算法中与特定子类相关的步骤。

协作

  • 类关系
  • 逻辑关系:
    • ConcreteClass靠Abstract来实现算法中不变的步骤。

权衡

  • 算法存在与模板方法类当中,拥有算法并保护算法,并且容易修改。专注于算法本身。
  • 模板方法对于子类而言可以将代码的复用最大化。
  • 提供了算法框架,新增添的类型可以容易加入。

实现

注意

  • 尽量减少原语操作。
  • 命名约定。

实现步骤

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
//模板方法的模板类,作为基类,子类必须事先其操作
public abstract class AbstractClass {
//模板方法,final避免子类改变算法顺序
final void templateMethod() {
//定义算法步骤,每个步骤由一个方法代表
primitiveOperation1();
primitiveOperation2();
concreteOperation1();
hook();
//利用钩子做判断影响算法流程
//if(hook()){
//}
}
//子类需要事先的操作
abstract void primitiveOperation1();

abstract void primitiveOperation2();

//由超类进行的实现
//算法的默认流程
final void concreteOperation1() {
}
//一个空的方法,作为钩子,子类视情况决定是否覆盖。
//子类有能力在算法的不同点进行挂钩
//当然也可以不是空的
void hook() {
}
}

钩子

  • 钩子可以让子类实现算法中可选的部分
  • 钩子对子类实现并不重要时可以忽略
  • 钩子可以让子类能够有机会对模板方法中某些即将发生的步骤做出反应

示例

相关模式

进阶

使用Lambda

反省总结

参考