模板方法设计模式属于行为型设计模式的一种,它的核心思路是在抽象类中定义一个算法的整体执行流程,也就是算法骨架,然后将其中某些可变的步骤声明为纯虚函数或者虚函数,交给具体的子类去实现。这样既能保证所有子类遵循统一的算法结构,又能让子类根据自身需求定制特定步骤的逻辑,避免代码重复。

模板方法模式的核心角色
实现模板方法模式主要包含两类核心角色:
- 抽象类:负责定义算法的整体骨架,也就是模板方法,同时声明算法中需要子类实现的步骤方法,还可以提供部分步骤的默认实现。
- 具体子类:继承抽象类,实现抽象类中声明的可变步骤方法,也可以根据需要重写父类的默认步骤实现。
C++实现步骤
1. 定义抽象类
抽象类中首先要定义模板方法,这个方法是公共的,一般用public权限修饰,内部调用各个步骤方法。步骤方法根据是否需要子类强制实现,可以声明为virtual纯虚函数或者普通虚函数。
#include <iostream>
#include <string>
// 抽象类:定义数据导出算法的骨架
class DataExporter {
public:
// 模板方法:定义数据导出的完整流程
void exportData() {
// 步骤1:读取数据
readData();
// 步骤2:处理数据
processData();
// 步骤3:导出数据
writeData();
// 步骤4:收尾工作
cleanUp();
}
virtual ~DataExporter() = default;
protected:
// 步骤方法:读取数据,默认实现
virtual void readData() {
std::cout << "默认读取数据:从本地文件读取" << std::endl;
}
// 步骤方法:处理数据,需要子类实现
virtual void processData() = 0;
// 步骤方法:导出数据,需要子类实现
virtual void writeData() = 0;
// 步骤方法:收尾工作,默认实现
virtual void cleanUp() {
std::cout << "默认收尾工作:关闭文件流" << std::endl;
}
};
2. 定义具体子类
具体子类继承抽象类,实现其中声明的纯虚函数,也就是必须定制的步骤逻辑,也可以根据需要重写父类的默认虚函数实现。
// 具体子类1:导出为CSV格式
class CsvDataExporter : public DataExporter {
protected:
void processData() override {
std::cout << "处理数据:按照CSV格式整理数据" << std::endl;
}
void writeData() override {
std::cout << "导出数据:将数据写入CSV文件" << std::endl;
}
};
// 具体子类2:导出为JSON格式
class JsonDataExporter : public DataExporter {
protected:
void readData() override {
std::cout << "重写读取数据:从数据库读取" << std::endl;
}
void processData() override {
std::cout << "处理数据:按照JSON格式整理数据" << std::endl;
}
void writeData() override {
std::cout << "导出数据:将数据写入JSON文件" << std::endl;
}
};
3. 客户端调用
客户端只需要创建具体子类的对象,调用模板方法即可,不需要关心算法的具体执行流程,只需要关注子类实现的特定步骤逻辑。
int main() {
// 导出CSV格式数据
DataExporter* csvExporter = new CsvDataExporter();
std::cout << "开始导出CSV数据:" << std::endl;
csvExporter->exportData();
delete csvExporter;
std::cout << std::endl;
// 导出JSON格式数据
DataExporter* jsonExporter = new JsonDataExporter();
std::cout << "开始导出JSON数据:" << std::endl;
jsonExporter->exportData();
delete jsonExporter;
return 0;
}
实现注意事项
- 模板方法一般声明为
public且非虚函数,避免子类修改算法的整体骨架,保证算法流程的统一性。 - 需要子类强制实现的步骤声明为纯虚函数,有默认实现的步骤声明为普通虚函数,方便子类按需重写。
- 如果某些步骤不希望子类重写,可以将其声明为
final,比如模板方法本身如果需要防止子类修改,可以加上final修饰。 - 抽象类的析构函数建议声明为虚函数,避免子类对象析构时出现内存泄漏问题。
适用场景
当遇到以下场景时,可以考虑使用模板方法设计模式:
- 有多个子类遵循相同的算法流程,但部分步骤的实现不同。
- 需要控制子类的扩展点,只允许子类修改算法的特定部分,不能修改整体流程。
- 需要避免代码重复,将相同逻辑提取到抽象类的模板方法中,减少子类中的重复代码。