18-模板方法模式

模板方法模式

2022年12月28日周三晚上测试(25道选择题——15分钟)

分析引入

请客吃饭示意图
image-20221226185441760 image-20221226185528491

模板方法模式的定义

image-20221226185613187

类行为型模式

  • 是一种基于继承的代码复用技术
  • 将一些复杂流程的实现步骤封装在一系列基本方法
  • 在抽象父类中提供一个称之为模板方法的方法来定义这些基本方法的执行次序,而通过其子类覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果

模板方法模式结构

image-20221226185719954
模板方法模式包含以下2个角色:
  • AbstractClass(抽象类)

    • 包含模版方法:定义函数方法调用的次序
  • ConcreteClass(具体子类)

模板方法模式实现

  • 模板方法 (Template Method)

    • 实现框架
  • 基本方法 (Primitive Method)

    • 抽象方法(Abstract Method)
    • 具体方法(Concrete Method)
    • 钩子方法(Hook Method)
钩子方法
  • “挂钩”方法: isXXX()或hasXXX(),返回类型为boolean类型

    • 通过钩子方法来确定某一步骤是否执行
    • 提供了一种子类对父类的反向控制机制
  • 空方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
……
//模板方法
public void template() {
open();
display();
//通过钩子方法来确定某一步骤是否执行
if(isPrint()) {
print();
}
}
 
//钩子方法
public boolean isPrint() {
return true;
}
……
抽象类典型代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public abstract class AbstractClass {
//模板方法
public void templateMethod() {
primitiveOperation1();
primitiveOperation2();
primitiveOperation3();
}
//基本方法—具体方法
public void primitiveOperation1() {
//实现代码
}

//基本方法—抽象方法
public abstract void primitiveOperation2();

//基本方法—钩子方法
public void primitiveOperation3()
{ }
}
具体子类典型代码
1
2
3
4
5
6
7
8
9
public class ConcreteClass extends AbstractClass {
public void primitiveOperation2() {
//实现代码
}

public void primitiveOperation3() {
//实现代码
}
}
实例类图
image-20221226190022242

image-20221226190526575这里的模版方法是handle()。

(1) Account:账户类,充当抽象类

(2) CurrentAccount:活期账户类,充当具体子类

(3) SavingAccount:定期账户类,充当具体子类

(4) Client:客户端测试类

引入配置文件

如果需要更换或增加具体子类,无须修改源代码,只需修改配置文件即可,符合开闭原则

配置文件代码
1
2
3
4
<?xml version="1.0"?>
<config>
<className>designpatterns.templatemethod.CurrentAccount</className>
</config>
实例类图2
image-20221226190727782 image-20221226190737714
抽象类代码
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
//designpatterns.templatemethod.hookmethod.DataViewer.java
package designpatterns.templatemethod.hookmethod;

public abstract class DataViewer {
//抽象方法:获取数据
public abstract void getData();

//具体方法:转换数据
public void convertData() {
System.out.println("将数据转换为XML格式。");
}

//抽象方法:显示数据
public abstract void displayData();

//钩子方法:判断是否为XML格式的数据
public boolean isNotXMLData() {
return true;
}

//模板方法
public void process() {
getData();
//如果不是XML格式的数据则进行数据转换
if (isNotXMLData()) {
convertData();
}
displayData();
}
}
实际类代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//designpatterns.templatemethod.hookmethod.XMLDataViewer.java
package designpatterns.templatemethod.hookmethod;

public class XMLDataViewer extends DataViewer {
//实现父类方法:获取数据
public void getData() {
System.out.println("从XML文件中获取数据。");
}

//实现父类方法:显示数据,默认以柱状图方式显示,可结合桥接模式来改进
public void displayData() {
System.out.println("以柱状图显示数据。");
}

//覆盖父类的钩子方法
public boolean isNotXMLData() {
return false;
}
}

模式优点

  • 在父类中形式化地定义一个算法,而由它的子类来实现细节的处理,在子类实现详细的处理算法时并不会改变算法中步骤的执行次序

  • 提取了类库中的公共行为,将公共行为放在父类中,而通过其子类来实现不同的行为

  • 可实现一种反向控制结构通过子类覆盖父类的钩子方法来决定某一特定步骤是否需要执行

  • 更换和增加新的子类很方便,符合单一职责原则和开闭原则

模式缺点

  • 需要为每一个基本方法的不同实现提供一个子类,如果父类中可变的基本方法太多,将会导致类的个数增加,系统会更加庞大,设计也更加抽象(可结合桥接模式

模式适用环境

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

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

  • 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制

课后思考

在模板方法模式中,钩子方法如何实现子类控制父类的行为?

钩子方法返回Boolean类型,结合条件语句判断是否执行父类某一步骤。

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2023-2024 Guijie Wang
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信