Design-Pattern-Template

模板模式(Template Pattern)是一种行为型设计模式,其核心思想是:在抽象父类中定义一个操作的算法骨架(模板),将部分步骤的具体实现延迟到子类中完成。通过这种方式,子类可以在不改变算法整体结构的前提下,重新定义算法中的某些特定步骤。

场景

假设需要生成三种格式的报表(PDF/Excel/HTML),初始方案简单定义了三个独立类分别处理数据生成与报表渲染。

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
public class PdfReportGenerator {
public void generate() {
List<String> rawData = fetchDataFromDB();
List<String> processedData = processData(rawData);
renderPdf(processedData);
saveToFile();
}

private List<String> fetchDataFromDB() {
...
}

private List<String> processData(List<String> rawData) {
...
}

private void renderPdf(List<String> processedData) {
...
}

private void saveToFile() {
...
}
}

public class ExcelReportGenerator {...}
public class HtmlReportGenerator {...}

对比三个类的代码,其中一部分代码是重复冗余的——所有报表的生成流程相同:

  1. 连接数据库获取数据
  2. 处理数据(过滤、排序、计算)
  3. 渲染为指定格式
  4. 输出文件

而客户端在调用生成器的方法时,不同生成器所属的类不同,因此可能要写多遍重复的调用代码。

1
2
3
4
5
6
7
8
PdfReportGenerator pdfGenerator = new PdfReportGenerator();
pdfGenerator.generate();

ExcelReportGenerator excelGenerator = new ExcelReportGenerator();
excelGenerator.generate();

HtmlReportGenerator htmlGenerator = new HtmlReportGenerator();
htmlGenerator.generate();

一个直观的改进思路是,先定义统一的生成器接口,再由各具体生成器类实现接口中的方法——这样客户端只需通过接口即可灵活引用各类具体生成器。不过,该方案仍无法解决三个具体生成器类中存在重复代码的问题。

模板模式

对于重复的代码和流程,可以将其抽取到一个抽象基类中。在上例中,就是将生成报表的过程,定义在抽象基类中。

1
2
3
4
5
6
7
8
9
10
11
12
13
public abstract class AbstractReportGenerator {
public void generate() {
List<String> rawData = fetchDataFromDB();
List<String> processedData = processData(rawData);
render(processedData);
saveToFile();
}

private abstract List<String> fetchDataFromDB();
private abstract List<String> processData(List<String> rawData);
private abstract void render(List<String> processedData)
private abstract void saveToFile();
}

在抽取的流程代码中,定义了操作流程的框架,依次调用了四个抽象方法。将方法声明为抽象方法可以强制子类实现其功能,体现不同子类的差异化。如果大部分子类都没明显差别,也可以在基类中提供默认实现,仅在少数子类去重写。

模板模式包含两个核心角色,抽象模板类定义了算法的骨架(模板方法),包含一系列按顺序执行的步骤。其中,不变的步骤由抽象类自身实现,可变的步骤声明为抽象方法,由子类实现。通常会将模板方法声明为 final,防止子类重写算法的整体结构。具体子类实现抽象模板类中定义的抽象方法,为算法的可变步骤提供具体实现。

至此模板模式已介绍完毕,结构简单得没有绘制类图的必要。模板模式的应用,有一个很有意思的特点:它在实践中往往悄无声息地落地。当我们在代码库中发现多个类存在大量重复代码或相似执行逻辑时,自然会想到将这些共性内容抽取到抽象基类中,仅在子类里实现差异化的具体细节。完成这样的改造后,代码结构其实就已经符合模板模式的设计思想了。这一过程的本质,正是模板模式的典型应用场景。硬要细究这两者的差异,模板模式最核心的特征在于定义了一个算法框架,并在框架中依次调用了抽象方法。

在一些框架中,会有预留的、可在指定方法前后执行的可重写方法,称为钩子函数。例如在Servlet中重写initdestroy方法,以支持Servlet的初始化和销毁资源。这也是模板模式的一种实践。

在模板模式的具体实现类中,其对多个抽象方法的实现通常是互相绑定,配套使用的。例如上例中声明的获取数据、处理数据、生成报表、保存文件四个抽象方法,其在实现时不能任意组合。生成pdf的具体类定义的处理数据方法,不该能替换成生成Excel的具体类中的处理数据方法,因为方法的返回值会被作为生成报表过程的入参。而若抽象方法的实现也需要支持能够互相替换任意组合,则可以采取策略模式,直接由调用方传入,而不是在模板方法中在定义抽象方法。

总结

模板模式将多个类中相同的流程步骤抽取到抽象基类中,形成算法骨架。在算法骨架中调用多个抽象方法,并在具体子类中实现这些抽象方法。

如果算法骨架中的抽象方法也需要可以替换具体实现,则可以使用策略模式。


Design-Pattern-Template
http://dracoyus.github.io/2025/11/21/Design-Pattern-Template/
作者
DracoYu
发布于
2025年11月21日
许可协议