一、模板设计模式概念
模板方法模式 (Template Method) 是一种行为设计模式, 它在超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。
模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术。,没有关联关系。 因此,在模板方法模式的类结构图中,只有继承关系。
模板方法模式需要开发抽象类和具体子类的设计师之间的协作。一个设计师负责给出一个算法的轮廓和骨架,另一些设计师则负责给出这个算法的各个逻辑步骤。
代表这些具体逻辑步骤的方法称做基本方法(primitive method);而将这些基本方法汇总起来的方法叫做模板方法(template method),这个设计模式的名字就是从此而来。
在模板方法模式中,首先父类会定义一个算法的框架,即实现算法所必须的所有方法。
其中,具有共性的代码放在父类的具体方法中。
各个子类特殊性的代码放在子类的具体方法中。但是父类中需要有对应抽象方法声明。
钩子方法可以让子类决定是否对算法的不同点进行挂钩。
适用场景
- 当你只希望客户端扩展某个特定算法步骤, 而不是整个算法或其结构时, 可使用模板方法模式。
- 当多个类的算法除一些细微不同之外几乎完全一样时, 你可使用该模式。 但其后果就是, 只要算法发生变化, 你就可能需要修改所有的类。
模板设计模式的结构:
- 抽象类 (AbstractClass) 会声明作为算法步骤的方法, 以及依次调用它们的实际模板方法。 算法步骤可以被声明为
抽象
类型, 也可以提供一些默认实现。- 具体类 (ConcreteClass) 可以重写所有步骤, 但不能重写模板方法自身。
代码如下:
问题:做一款数据挖掘的程序,需要支持不同格式的数据文件,虽然文件格式不同,但读取文件、解析数据、处理数据、输出结果等步骤大致相同,
解决方法:定义一个算法骨架,将其中一些步骤延迟到子类中实现,模板方法模式使得子类可以不改变算法的结构即可重定义算法中的某些步骤。
#include <iostream>
#include <string>
class DataMiner
{
public:
// 模板方法
void mineData(const std::string& path)
{
openFile(path);
extractData();
makeReport();
hook1();
closeFile();
}
protected:
virtual void openFile(const std::string& path) = 0; // 不用 const
void extractData() const
{
std::cout << "DataMiner: 从字符串提取相关数据" << std::endl;
// 使用 m_str 进行数据提取的逻辑
}
void makeReport() const
{
std::cout << "DataMiner: 生成报告" << std::endl;
}
virtual void closeFile() const = 0;
virtual void hook1() const {}
protected:
std::string m_str = "";
};
class PDFDataMiner : public DataMiner
{
public:
void openFile(const std::string& path) override
{
m_str = "PDF内容"; // 假设这里存储PDF内容
std::cout << "PDFDataMiner: 打开PDF文件 " << path << std::endl;
}
void closeFile() const override
{
std::cout << "PDFDataMiner: 关闭文件" << std::endl;
}
};
class WordDataMiner : public DataMiner
{
public:
void openFile(const std::string& path) override
{
m_str = "Word内容"; // 假设这里存储Word内容
std::cout << "WordDataMiner: 打开Word文件 " << path << std::endl;
}
void closeFile() const override
{
std::cout << "WordDataMiner: 关闭文件" << std::endl;
}
void hook1() const override
{
std::cout << "WordDataMiner: hook1" << std::endl;
}
};
void clientCode(DataMiner* miner, const std::string& path)
{
miner->mineData(path);
}
int main()
{
PDFDataMiner pdf;
clientCode(&pdf, "example.pdf");
std::cout << std::endl;
WordDataMiner word;
clientCode(&word, "example.docx");
return 0;
}
二、与其他模式的关系
- 工厂方法模式 (opens new window)是模板方法模式 (opens new window)的一种特殊形式。 同时, 工厂方法可以作为一个大型模板方法中的一个步骤。
- 模板方法 (opens new window)基于继承机制: 它允许你通过扩展子类中的部分内容来改变部分算法。 策略模式 (opens new window)基于组合机制: 你可以通过对相应行为提供不同的策略来改变对象的部分行为。 模板方法在类层次上运作, 因此它是静态的。 策略在对象层次上运作, 因此允许在运行时切换行为。