设计模式之禅——模板方法模式

引:少写代码,大家一定觉得很有吸引力。而且还是先确定一个框架,再写其中的部分,这么结构清晰地写代码,大家一定会觉得更有吸引力,那么我想模板方法模式可以达到你的需求。

定义

定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。——行为类

下面是他的通用类图:

templateMethod

其中AbstractClass叫做抽象模板,它的方法分为两类

  • 基本方法:由子类实现的方法,并且在模板方法被调用。
  • 模板方法:一般是一个具体方法,实现对基本方法的调度,完成固定的逻辑。

为了防止恶意的操作,一般模板方法都加上final关键字,不允许被覆写。

而ConcreteClass属于具体模板,实现父类所定义的抽象方法。

下面再看看他的通用代码:

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
// 抽象模板类
public abstract class AbstrctClass {
// 基本方法
protected abstract void doSomething();
// 基本方法
protected abstract void doAngthing();
// 模板方法
final public void templateMethod() {
// 调用基本方法,完成相关逻辑
this.doAnything();
this.doSomething();
}
}

// 具体模板类
public class ContreteClass1 extends AbstractClass {
// 实现基本方法
@Override
protected void doAngthing() {
// 业务逻辑处理
}

@Override
protected void doSomething() {
// 业务逻辑处理
}
}

public class ContreteClass2 extends AbstractClass {
// 实现基本方法
@Override
protected void doAngthing() {
// 业务逻辑处理
}

@Override
protected void doSomething() {
// 业务逻辑处理
}
}

// 场景类
public class Client {
public static void main (String[] args) {
AbstractClass class1 = new ConcreteClass1();
AbstractClass class2 = new ConcreteClass2();
// 调用模板方法
class1.templateMethod();
class2.templateMethod();
}
}

抽象模板中的基本方法尽量设计为protected类型,符合迪米特原则。实现类若非必要,尽量不要扩大父类中的访问权限。

应用

优点

  1. 封装不变部分,扩展可变部分。
  2. 提取公共部分代码,便于维护。
  3. 行为由父类控制,子类实现。符合开闭原则。

缺点

是优点也是缺点:子类对父类产生了影响。

使用场景

  1. 多个子类有公有的方法,并且逻辑基本相同。
  2. 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。
  3. 重构时,模板方法模式一个常用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。有了钩子方法的模板方法模式才是完美的。

ps:钩子方法就是子类实现的一个方法,可以利用其返回值决定公共部分的执行结果。

最佳实践

  1. 父类如何调用子类的方法(极度不建议这么做)

    • 把子类传递到父类的有参构造函数中,然后调用。
    • 使用反射的方式调用。
    • 父类调用子类的静态方法。

      但是通过模板方法模式就可以变相地实现父类调用子类的方法。

  2. 在开源框架中,它提供了一个抽象类,然后开源框架写了一堆子类。如果你需要扩展,可以继承这个抽象类,然后覆写protected方法,再调用一个类似execute方法,就完成了扩展开发。相信大家一定深有感触。