当前位置: 首页 > news >正文

【第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

#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;  // 实现原语操作1void PrimitiveOperation2() override;  // 实现原语操作2
};// 具体子类2,实现原语操作
class ConcreteClass2 : public AbstractClass {
public:ConcreteClass2() {}~ConcreteClass2() {}
protected:void PrimitiveOperation1() override;  // 实现原语操作1void PrimitiveOperation2() override;  // 实现原语操作2
};#endif //~ _TEMPLATE_H_

Template.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

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


http://www.mrgr.cn/news/93112.html

相关文章:

  • 【每日学点HarmonyOS Next知识】web滚动、事件回调、selectable属性、监听H5内部router、Grid嵌套时高度设置
  • 双目系统求坐标系A到坐标系B的旋转矩阵和平移向量——C++代码实现
  • 测试工程师的DeepSeek提效3:质保中的应用
  • io标准函数和时间函数day2
  • 认识线程
  • SpaCy处理NLP的详细工作原理及工作原理框图
  • 《AJAX:前端异步交互的魔法指南》
  • Qt之QGraphicsView图像操作
  • Python----数据分析(Matplotlib三:绘图二:箱图,散点图,饼图,热力图,3D图)
  • day3作业
  • 【pta】1031 查验身份证
  • windows下使用Hyper+wsl实现ubuntu下git的平替
  • 多视图几何--2单应矩阵-2.0从0-1理解并计算单应矩阵
  • 测试工程师的DeepSeek提效4:测试效能提升应用
  • Keepalived 入门详解:高可用集群部署最佳实践!
  • ASP.NET Core JWT认证与授权
  • servlet tomcat
  • 使用ast获取py文件中所有函数与类名
  • 【每日学点HarmonyOS Next知识】Web Header更新、状态变量嵌套问题、自定义弹窗、stack圆角、Flex换行问题
  • VTP故障诊断与排除