设计模式(4)——模板方法模式

本文介绍模板方法模式的概念和应用。

基本思想和原则

定义一个操作的算法框架,将框架内的步骤延迟到子类实现,使子类可以在不改变算法框架的情况下重写算法的各个步骤。

如果某个抽象类的方法具有一个固定的流程,流程中有多个步骤,但各个步骤的具体实现不同,我们就可以使用模板方法模式在抽象类中将这些步骤封装在一个方法内。子类只需要实现各个步骤,不需要修改这个方法。由于模板方法模式在父类中定义了算法框架,只是其中各个步骤的具体实现延迟到了子类,因此是一个模板,可以由子类套用。

动机

如果有一个类体系,所有子类都实现了同一个方法,而这个方法可以抽象为几个固定的步骤,在当前这种设计下,每个子类的代码在一定程度上是有重复的。可以使用模板方法模式重构。

实现

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
public abstract class Computer {
protected abstract void boot();
protected abstract void runningProcesses();
protected abstract void powerOff();
public final void run() {
this.boot();
this.runningProcesses();
this.powerOff();
}
}

public class AppleComputer extends Computer {
protected void boot() {
System.out.println("AppleComputer boot...");
}

protected void runningProcesses() {
System.out.println("AppleComputer running processes...");
}

protected void powerOff() {
System.out.println("AppleComputer power off...");
}
}

public class DellComputer extends Computer {
protected void boot() {
System.out.println("DellComputer boot...");
}

protected void runningProcesses() {
System.out.println("DellComputer running processes...");
}

protected void powerOff() {
System.out.println("DellComputer power off...");
}
}

public class Test {
public static void main(String[] args) {
AppleComputer appleComputer = new AppleComputer();
DellComputer dellComputer = new DellComputer();

appleComputer.run();
System.out.println("\n");
dellComputer.run();
}
}

运行结果:

1
2
3
4
5
6
7
AppleComputer boot...
AppleComputer running processes...
AppleComputer power off...

DellComputer boot...
DellComputer running processes...
DellComputer power off...

优点

模板方法模式将一个算法框架抽象出来,在父类实现,子类只需要实现算法中的相应步骤。我们将公共代码提取到父类,当实现子类时就不会存在重复代码。在增加子类时,不需要修改已有的任何类,符合开闭原则,其代码的复用性和可维护性都很好。

需要注意的是,模板方法在Java中经常使用final修饰以防止子类覆写,各个步骤方法一般用protected修饰,这样不会将内部步骤暴露给外部,符合迪米特法则。

缺点

严格来说模板方法模式没有什么很明显的缺点,唯一需要注意的是识别使用模板方法模式的时机,因为在超类中定义模板方法后,不应在子类覆写,如果一些子类有非常特殊的流程,比如在固定流程中间穿插某些步骤,则模板方法模式可能不再适用于这个类体系。