【第13节】C++设计模式(行为模式)-Template(模板)模式

一、问题的提出

Template 模式:算法步骤框架与细节实现的分离

假设我们正在开发一个文档处理系统,需要支持多种文档格式的导出(如 PDF、Word、HTML 等)。每种文档格式的导出过程大致相同,都包含以下步骤:

(1)准备文档内容:获取需要导出的文档数据。

(2)格式化文档:根据具体格式对文档进行格式化(如 PDF 的特殊排版、Word 的样式设置等)。

(3)生成文件:将格式化后的文档保存为具体格式的文件。

(4)清理资源:释放导出过程中使用的资源。

虽然每种文档格式的导出步骤相同,但具体的实现细节(如格式化、文件生成)可能不同。这时,Template 模式 就可以派上用场。

在不同的对象中有不同的细节实现,但逻辑步骤是相同的。Template 模式提供了一种实现框架,通过继承的方式将各个步骤方法的框架放在抽象基类中,并定义好细节的接口,子类则负责实现这些细节。

二、模式选择

解决上述问题可以采用两种模式:Template 模式 和 Strategy 模式本文主要讨论 Template 模式。Template 模式通过继承的方式实现算法框架与细节实现的分离,而 Strategy 模式则是通过组合(委托)的方式来解决类似的问题。

Template 模式的核心思想是利用面向对象中的多态性,实现算法框架与细节实现的松耦合。Template 模式通过继承来实现这一点,但由于继承是一种强约束性的关系,因此也会带来一些不便之处。

三、代码实现

下面是一个完整的 Template 模式的实现示例,采用 C++ 编写。

代码实现

Template.h

cpp 复制代码
#ifndef _TEMPLATE_H_
#define _TEMPLATE_H_

// 抽象基类,定义算法框架
class AbstractClass {
public:
    virtual ~AbstractClass() {}
    void TemplateMethod();  // 模板方法,定义算法框架
protected:
    virtual void PrimitiveOperation1() = 0;  // 原语操作1,子类实现
    virtual void PrimitiveOperation2() = 0;  // 原语操作2,子类实现
    AbstractClass() {}
};

// 具体子类1,实现原语操作
class ConcreteClass1 : public AbstractClass {
public:
    ConcreteClass1() {}
    ~ConcreteClass1() {}
protected:
    void PrimitiveOperation1() override;  // 实现原语操作1
    void PrimitiveOperation2() override;  // 实现原语操作2
};

// 具体子类2,实现原语操作
class ConcreteClass2 : public AbstractClass {
public:
    ConcreteClass2() {}
    ~ConcreteClass2() {}
protected:
    void PrimitiveOperation1() override;  // 实现原语操作1
    void PrimitiveOperation2() override;  // 实现原语操作2
};

#endif //~ _TEMPLATE_H_

Template.cpp

cpp 复制代码
#include "Template.h"
#include <iostream>
using namespace std;

// 模板方法,定义算法框架
void AbstractClass::TemplateMethod() {
    this->PrimitiveOperation1();
    this->PrimitiveOperation2();
}

// ConcreteClass1 的原语操作实现
void ConcreteClass1::PrimitiveOperation1() {
    cout << "ConcreteClass1...PrimitiveOperation1" << endl;
}

void ConcreteClass1::PrimitiveOperation2() {
    cout << "ConcreteClass1...PrimitiveOperation2" << endl;
}

// ConcreteClass2 的原语操作实现
void ConcreteClass2::PrimitiveOperation1() {
    cout << "ConcreteClass2...PrimitiveOperation1" << endl;
}

void ConcreteClass2::PrimitiveOperation2() {
    cout << "ConcreteClass2...PrimitiveOperation2" << endl;
}

main.cpp

cpp 复制代码
#include "Template.h"
#include <iostream>
using namespace std;

int main(int argc, char* argv[]) {
    AbstractClass* p1 = new ConcreteClass1();  // 创建 ConcreteClass1 对象
    AbstractClass* p2 = new ConcreteClass2();  // 创建 ConcreteClass2 对象

    p1->TemplateMethod();  // 调用 ConcreteClass1 的模板方法
    p2->TemplateMethod();  // 调用 ConcreteClass2 的模板方法

    delete p1;
    delete p2;

    return 0;
}

代码说明

Template 模式的实现非常简单,其核心思想是将通用算法(逻辑)封装在抽象基类中,而将算法的具体细节交给子类实现(通过多态性)。需要注意的是,我们将原语操作(细节算法)定义为 `protected` 成员,这样它们只能被模板方法调用,子类可以重写这些方法。

四、总结讨论

Template 模式是一种简单但应用广泛的设计模式。通过继承的方式,Template 模式实现了算法的异构性,其关键点在于将通用算法封装在抽象基类中,而将不同的算法细节放到子类中实现。

Template 模式还实现了一种反向控制结构,这符合面向对象设计中的 **依赖倒置原则(DIP)**。DIP 的核心思想是高层模块(父类)调用低层模块(子类)的操作,低层模块实现高层模块声明的接口。这样,控制权在父类(高层模块),而低层模块则依赖于高层模块。

然而,继承的强约束性也带来了 Template 模式的一些不足。例如,假设我们想要创建一个 `AbstractClass` 的变体 `AnotherAbstractClass`,并且两者只是通用算法不同,而原语操作希望复用 `AbstractClass` 的子类实现。由于 `ConcreteClass` 继承自 `AbstractClass`,它继承了 `AbstractClass` 的通用算法,因此 `AnotherAbstractClass` 无法复用 `ConcreteClass` 的实现,因为后者并不是继承自前者。

Template 模式暴露的问题正是继承所固有的问题。相比之下,Strategy 模式(后面章节介绍)通过组合(委托)来达到类似的效果,尽管这会带来一定的空间和时间上的开销。关于 Strategy 模式的详细讨论,可以参考相关的设计模式解析。

Template 模式通过继承的方式实现了算法框架与细节实现的分离,适用于那些算法框架固定但细节实现可能变化的场景。尽管它简单易用,但在某些情况下,继承的强约束性可能会带来一些不便。在实际应用中,开发者可以根据具体需求选择 Template 模式或 Strategy 模式来实现算法的灵活性和复用性。

相关推荐
TechNomad23 分钟前
二、Visual Studio2022配置OpenGL环境
c++·opengl
杨校1 小时前
杨校老师课堂之备战信息学奥赛算法背包DP练习题汇总
c++·算法·信息学竞赛·dp算法
居然是阿宋1 小时前
Java/Kotlin 开发者如何快速入门 C++
java·c++·kotlin
weixin_468466851 小时前
C++、C#、python调用OpenCV进行图像处理耗时对比
c++·图像处理·python·opencv·c#·机器视觉·opencvsharp
ChoSeitaku2 小时前
NO.24十六届蓝桥杯备战|二维数组八道练习|杨辉三角|矩阵(C++)
c++·线性代数·矩阵
_GR2 小时前
2017年蓝桥杯第八届C&C++大学B组真题及代码
c++·职场和发展·蓝桥杯
commonbelive2 小时前
c语言、c++怎么将string类型数据转成int,怎么将int转成string
c语言·c++
showmeyourcode0.o3 小时前
QT——对象树
c++·qt
三天不学习3 小时前
23种设计模式之 【建造者模式】
设计模式·c#·建造者模式
Halsey Walker3 小时前
QT实现单个控制点在曲线上的贝塞尔曲线
c++·qt