设计模式-模板方法模式

模板方法模式(Template Method): 顾名思义, 它定义了一个模板, 只用填写模板上的某些内容即可, 类似于填空题或者表格填写. 具体定义为: 定义了一个操作中, 某个部分的骨架, 把变动部分放到子类去实现, 不改变骨架的前提下, 子类可以灵活拓展, 是一种行为型的设计模式.

设计模式-概述

结构

这玩意有这么几个部分组成:

  1. 抽象类(AbstractClass) : 定义了一个程序执行的骨架, 填空题的题干.
  2. 具体子类(ConcreteClass) : 定义了骨架中缺失的部分, 需要填写的空.

template-method-1

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
@startuml template-method-1
!include ./common.cuml

Class(AbstractClass,"抽象类") << abstract >> {
+ abstractMethod1() : void abstract
+ abstractMethod2() : void abstract
+ specificMethod1() : void
+ specificMethod2() : void
+ specificMethod3() : void
+ mainMethod() : void
}

Class(ConcreteClassA,"子类A") {
+ abstractMethod1() : void
+ abstractMethod2() : void
}

Class(ConcreteClassB,"子类B") {
+ abstractMethod1() : void
+ abstractMethod2() : void
}

note as N1
public void mainMethod() {
specificMethod1();
abstractMethod1();
specificMethod2();
abstractMethod2();
specificMethod3();
}
end note

AbstractClass <|.. ConcreteClassA
AbstractClass <|.. ConcreteClassB
N1 .. AbstractClass

@enduml

代码实现

  1. 有一个父类, 定义了一个模板方法mainMethod(), 方法中有其他5个方法, 3个是骨架方法, 2个是拓展方法(交给子类实现)
  2. 有两个子类, 实现了父类的方法, 各自的实现不同.
  3. 执行者, 使用不同的子类, 执行mainMethod()方法, 可以发现:执行过程中, 有两步操作是由子类定义的.
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
public class Main2 {
public static void main(String[] args) {
AbstractClass a = new ConcreteClassA();
a.mainMethod();
AbstractClass b = new ConcreteClassB();
b.mainMethod();
}
}

abstract class AbstractClass {
public abstract void abstractMethod1();

public abstract void abstractMethod2();

private void specificMethod1() {
System.out.println("AbstractClass.specificMethod1");
}

private void specificMethod2() {
System.out.println("AbstractClass.specificMethod2");
}

private void specificMethod3() {
System.out.println("AbstractClass.specificMethod3");
}

void mainMethod() {
specificMethod1();
abstractMethod1();
specificMethod2();
abstractMethod2();
specificMethod3();
}
}

class ConcreteClassA extends AbstractClass {

@Override
public void abstractMethod1() {
System.out.println("ConcreteClassA.abstractMethod1");
}

@Override
public void abstractMethod2() {
System.out.println("ConcreteClassA.abstractMethod2");
}
}

class ConcreteClassB extends AbstractClass {

@Override
public void abstractMethod1() {
System.out.println("ConcreteClassB.abstractMethod1");
}

@Override
public void abstractMethod2() {
System.out.println("ConcreteClassB.abstractMethod2");
}
}

使用场景

  1. 这个设计模式适用于整体步骤很固定的, 不会有变动, 比如同试卷的同道填空题, 大家都是一样的, 不会出现每个人各一种题目.
  2. 当各个同级子类中, 有相似的执行流程.
  3. 仅仅在流程中的某一步需要自定义.
  4. 并且这样的子类有很多, 或者未来会有很多时.

具体应用

  1. 我的任职公司(轻轻教育), 有个地方需要对接第三方API, 调用他们的各种智能分析, 各种分析任务流程大致是相同的(任务入队->并发控制->任务出队->修改状态为执行中->调用第三方执行->获取结果->判断是否获取成功->保存结果到各自表->任务标记结果), 唯一不同的地方有两个:一个是调用第三方执行, 另外一个是:保存结果到各自表. 这里用到了模板方法模式, 父类封装了大致流程, 暴露两个abstract的方法, 交给子类实现, 各个子类中submit()方法用来拼不同参数并调用不同的接口, saveResult()方法用来获取到一个结果, 并保存.

  2. MybatisBaseExecutor接口中的模板方法模式:

    • BaseExecutor中主要提供了缓存管理和事务管理的基本功能, 有4个子类:
    • SimpleExecutor 执行Mapper语句时默认使用的
    • ReuseExecutor 提供了 Statement 重用的功能,通过 statementMap 字段缓存使用过的 Statement 对象进行重用,可以减少SQL预编译以及创建和销毁 Statement 对象的开销,从而提高性能
    • BatchExecutor 实现了批处理多条SQL语句的功能,在客户端缓存多条SQL并在合适的时机将多条SQL打包发送给数据库执行,从而减少网络方面的开销,提升系统的性能
    • ClosedExecutor 只是某个类的一个内部类
      template-method-2