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

news/2025/3/6 7:00:12/

一、问题的提出

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.ppmy.cn/news/1577002.html

相关文章

国产替代新篇章:领麦微红外测温传感器赋能3D打印精准制造

在3D打印领域&#xff0c;精准的温度控制是确保打印质量、提高打印效率的关键。领麦微红外温度传感器作为一款性能出色的测温传感器&#xff0c;凭借其非接触、快速响应、高精度测温特性&#xff0c;成为了光敏性3D打印技术的精准守护者。 快速响应 领麦微红外温度传感器在光…

AR配置静态IP双链路负载分担示例

AR配置静态IP双链路负载分担示例 适用于大部分企业网络出口 业务需求&#xff1a; 运营商1分配的接口IP为100.100.1.2&#xff0c;子网掩码为255.255.255.252&#xff0c;网关IP为100.100.1.1。 运营商2分配的接口IP为200.200.1.2&#xff0c;子网掩码为255.255.255.248&am…

AI浏览器BrowserUse:安装与配置(四)

概述 在前一篇文章中&#xff0c;我们讨论了 AI 浏览器的基本概念以及如何利用 Browser Use 项目构建智能浏览器。现在&#xff0c;我们进入了安装和配置的环节。在这一篇文章中&#xff0c;我们将详细介绍如何安装 Browser Use Web UI 项目&#xff0c;配置环境&#xff0c;启…

使用Perl和库WWW::Curl的爬虫程序

使用 Perl 和 WWW::Curl 库编写爬虫程序是一个常见的做法。WWW::Curl 是 Perl 对 libcurl 库的封装&#xff0c;提供了强大的 HTTP 请求功能&#xff0c;可以帮助你抓取网页内容。 以下是如何使用 Perl 和 WWW::Curl 库编写一个简单的爬虫程序的步骤&#xff1a; 1. 安装 WWW:…

2024提示词工程师进阶指南:从基础规范到技术参数配置

一、提示词设计的核心原则 1.1 目标导向性原则 有效的提示词必须包含明确的任务目标&#xff0c;这是与AI模型对话的基础。建议采用「动词对象限定条件」的结构框架&#xff0c;例如&#xff1a; 错误示例&#xff1a;”帮我写点东西”优秀示例&#xff1a;”用简明易懂的商…

C#基础及标准控件的使用,附登录案例

C#基础及标准控件的使用,附登录案例 一、项目整体结构1. 项目结构2. 程序结构二、项目的基础操作三、常用的windows标准控件1. 按钮控件的使用2. 项目资源的配置(如图标)3. 文本控件的使用四、WinForm程序生成及运行调试1. Debug调试模式下生成2. Release发布模式下生成3. 程…

【每日论文】How far can we go with ImageNet for Text-to-Image generation?

下载PDF或查看论文&#xff0c;请点击&#xff1a;LlamaFactory - huggingface daily paper - 每日论文解读 | LlamaFactory | LlamaFactory 摘要 近年来&#xff0c;通过在大规模数据集上训练&#xff0c;文本到图像&#xff08;T2I&#xff09;生成模型已经取得了显著成果&a…

MySQL8 忘记密码

太尴尬了&#xff0c;好久没用MySQL已经忘记了用户密码&#xff0c;那么在Windows环境下遗忘了该怎么办呢&#xff1f;跟着小铃铛来看看。 解决方案 第一步&#xff1a;首先停止MySQL服务 PS D:\program_23\mysql-8.0.33-winx64\bin> net stop mysql mysql 服务正在停止. …