【第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 模式来实现算法的灵活性和复用性。

相关推荐
程序员老陆11 小时前
std::experimental::when_any 深度解析:等待“第一个完成”的异步组合原语
c++·多线程
Rabitebla12 小时前
【Linux系统编程】指令(三):创建、删除、复制、移动、看内容
linux·数据结构·c++·算法
程序员老陆12 小时前
CMake 常用关键字与命令全景:从 set到 target_link_options的现代工程视角
c++·cmake·程序开发
码匠许师傅13 小时前
【C++三方组件】cxxopts:轻量首选的命令行解析
c++
hansang_IR13 小时前
【讲解】CSP-S2026 第一轮初赛
c++·算法
Methy13 小时前
IoTHub半个月崩了五次?都是裸rethrow惹的祸
服务器·c++·后端
Zane199413 小时前
策略模式现在该不该上?一次讲清楚过度设计和设计不足怎么找平衡
设计模式
我不会起名字32213 小时前
一天一道力扣Hot100(36):深度优先算法---组合总和
数据结构·c++·后端·python·算法·go
纪念 22913 小时前
c++类和对象(四)
开发语言·c++
汉克老师13 小时前
GESP2026年9月认证C++六级( 第三部分编程题(2、分树规划))精讲
c++·gesp·小学生·学c++编程