【C++设计模式】第二十一篇:模板方法模式(Template Method)
注意:复现代码时,确保 VS2022 使用 C++17/20 标准以支持现代特性。
算法骨架的标准化定义
1. 模式定义与用途
核心思想
- 模板方法模式:在父类中定义算法的骨架,将某些步骤延迟到子类实现,使得子类不改变算法结构即可重写特定步骤。
- 关键用途:
1.代码复用:提取多个类的共同流程到父类。
2.流程标准化:确保算法步骤的执行顺序不变。
3.扩展性:子类仅需关注差异化的实现细节。
经典场景
- 数据解析框架(固定解析流程,支持多种格式)。
- 游戏角色行为(如攻击流程统一,子类实现不同攻击方式)。
- 自动化测试框架(测试步骤固定,具体操作可定制)。
2. 模式结构解析
UML类图
+---------------------+
| AbstractClass |
+---------------------+
| + templateMethod() |
| + step1() |
| + step2() |
| + step3() |
+---------------------+ ^ | | +-----------------+ | ConcreteClass | +-----------------+ | + step2() | +-----------------+
角色说明
AbstractClass:抽象类,定义模板方法(算法骨架)和抽象步骤(step2())。ConcreteClass:具体子类,实现父类定义的抽象步骤。
3. 现代C++实现示例
场景:数据报告生成器
步骤1:定义抽象模板类
#include <iostream>
#include <memory> // 抽象报告生成器
class ReportGenerator {
public: virtual ~ReportGenerator() = default; // 模板方法(固定流程) void generateReport() { collectData(); processData(); // 抽象步骤 formatReport(); saveReport(); } protected: // 通用步骤(已实现) void collectData() { std::cout << "收集数据...\n"; } virtual void processData() = 0; // 抽象步骤 void formatReport() { std::cout << "格式化报告为PDF...\n"; } void saveReport() { std::cout << "保存报告到服务器\n"; }
};
步骤2:实现具体子类
// 销售报告生成器
class SalesReport : public ReportGenerator {
protected: void processData() override { std::cout << "处理销售数据:计算总销售额和增长率\n"; }
}; // 库存报告生成器
class InventoryReport : public ReportGenerator {
protected: void processData() override { std::cout << "处理库存数据:分析缺货商品和周转率\n"; } // 扩展:重写非抽象步骤 void saveReport() { std::cout << "保存报告到本地数据库\n"; }
};
步骤3:客户端代码
int main() { SalesReport salesReport; salesReport.generateReport(); /* 输出: 收集数据... 处理销售数据:计算总销售额和增长率 格式化报告为PDF... 保存报告到服务器 */ InventoryReport inventoryReport; inventoryReport.generateReport(); /* 输出: 收集数据... 处理库存数据:分析缺货商品和周转率 格式化报告为PDF... 保存报告到本地数据库 */
}
4. 应用场景示例
场景1:游戏角色攻击流程
class Character {
public: void attack() { aim(); loadWeapon(); // 抽象方法 fire(); } protected: virtual void loadWeapon() = 0; void aim() { std::cout << "瞄准目标\n"; } void fire() { std::cout << "开火!\n"; }
}; class Sniper : public Character {
protected: void loadWeapon() override { std::cout << "装填狙击步枪\n"; }
}; class Mage : public Character {
protected: void loadWeapon() override { std::cout << "凝聚魔法能量\n"; }
};
场景2:跨平台文件解析器
class FileParser {
public: void parse(const std::string& path) { openFile(path); validateHeader(); // 抽象方法 extractContent(); closeFile(); } protected: virtual void validateHeader() = 0; void openFile(const std::string& path) { /* 通用实现 */ } void extractContent() { /* 通用实现 */ } void closeFile() { /* 通用实现 */ }
}; class XMLParser : public FileParser {
protected: void validateHeader() override { std::cout << "验证XML头部...\n"; }
};
5. 优缺点分析
| 优点 | 缺点 |
|---|---|
| 避免重复代码,提升复用性 | 父类修改可能影响所有子类 |
| 确保核心流程不可变 | 子类可能被迫实现无用的抽象方法 |
| 通过钩子方法(Hook)灵活扩展 | 过度继承可能导致类层次复杂 |
6. 调试与优化策略
调试技巧(VS2022)
1. 跟踪模板方法执行流程:
- 在
generateReport()方法内设置断点,验证步骤顺序是否正确。
2. 验证子类方法覆盖:
- 使用 重写指示符
override确保子类正确实现抽象方法。
性能优化
1. 钩子方法(Hook):
- 在父类中提供空实现的钩子方法,允许子类选择性扩展。
class ReportGenerator {
protected: virtual void preSaveHook() {} // 钩子方法 void saveReport() { preSaveHook(); std::cout << "保存报告到服务器\n"; }
}; class InventoryReport : public ReportGenerator {
protected: void preSaveHook() override { std::cout << "压缩报告数据...\n"; }
};
2. 模板方法拆分:
- 将大型模板方法拆分为多个小方法,提升可维护性。
相关文章:
【C++设计模式】第二十一篇:模板方法模式(Template Method)
注意:复现代码时,确保 VS2022 使用 C17/20 标准以支持现代特性。 算法骨架的标准化定义 1. 模式定义与用途 核心思想 模板方法模式:在父类中定义算法的骨架,将某些步骤延迟到子类实现,使得子类不改变算法结构即可…...
【机器学习】基于t-SNE的MNIST数据集可视化探索
一、前言 在机器学习和数据科学领域,高维数据的可视化是一个极具挑战但又至关重要的问题。高维数据难以直观地理解和分析,而有效的可视化方法能够帮助我们发现数据中的潜在结构、模式和关系。本文以经典的MNIST手写数字数据集为例,探讨如何利…...
【Pycharm】Pycharm无法复制粘贴,提示系统剪贴板不可用
我也没有用vim的插件,检查了本地和ubutnu上都没有。区别是我是远程到ubutnu的pycharm,我本地直接控制windowes的pycharm是没问题的。现象是可以从外部复制到pycharm反之则不行。 ctl c ctlv 以及右键 都不行 参考:Pycharm无法复制粘贴&…...
基于python+django+vue.js开发的医院门诊管理系统/医疗管理系统源码+运行
功能介绍 平台采用B/S结构,后端采用主流的Python语言进行开发,前端采用主流的Vue.js进行开发。源码 功能包括:医生管理、科室管理、护士管理、住院管理、药品管理、用户管理、日志管理、系统信息模块。 源码地址 https://github.com/geee…...
Spring Boot整合RabbitMQ极简教程
一、消息队列能解决什么问题? 异步处理:解耦耗时操作(如发短信、日志记录)流量削峰:应对突发请求,避免系统过载应用解耦:服务间通过消息通信,降低依赖 二、快速整合RabbitMQ 1. 环…...
Flink-学习路线
最近想学习一下Flink,公司的实时需求还是不少的,因此结合ai整理了一份学习路线,记录一下。 当然,公司也有Scala版本Flink框架,也学习了一下。这里只说Java版本 1. Java基础 目标: 掌握Java编程语言的基础知识。 内容…...
Atcoder ABC397-D 题解
https://atcoder.jp/contests/abc397/tasks/abc397_dhttps://atcoder.jp/contests/abc397/tasks/abc397_d 题目描述: 确定是否存在一对正整数,使得 思路: 首先对方程进行转化 设 即 接下来确定的范围 根据立方差公式 因此,我们可以从到来…...
K8S学习之基础二十七:k8s中daemonset控制器
k8s中DaemonSet控制器 DaemonSet控制器确保k8s集群中,所有节点都运行一个相同的pod,当node节点增加时,新节点也会自动创建一个pod,当node节点从集群移除,对应的pod也会自动删除。删除DaemonSet也会删除创建的pod。…...
电机控制常见面试问题(八)
文章目录 一、解释什么是矢量控制及其优势二、 如何设计一个电机控制系统的开环和闭环控制?请给出具体案例三.如何通过软件模拟来优化电机控制设计四. 请解释电机过流保护过压保护过温保护等保护机制五.你熟悉哪些电机驱动拓扑结构六.解释空间适量脉宽调制的原理 一…...
保持docker内容器一直运行
首先:确保Docker服务配置为开机自启,这样当虚拟机启动时,Docker也会启动,并按照设定的重启策略自动启动相关容器。 sudo systemctl enable docker 创建容器时: 当你使用docker run命令启动容器时,可以添…...
神经网络的基本知识
感知机 输入:来自其他 n 个神经元传递过来的输入信号 处理:输入信号通过带权重的连接进行传递, 神经元接受到总输入值将与神经元的阈值进行比较 输出:通过激活函数的处理以得到输出 感知机由两层神经元组成, 输入层接受外界输入信号传递给…...
PostgreSQL技术内幕26:PG聚合算子实现分析
文章目录 0.简介1.概念说明2.朴素聚集3.Group by聚集3.1 哈希聚集3.2 分组聚集 0.简介 聚合算子在聚合函数在数据分析、报告生成和统计计算中扮演着重要角色,通过对多行数据进行计算,将多个输入值压缩为单一输出值,如求和、平均值、计数等。…...
【RS】OneRec快手-生成式推荐模型
note 本文提出了一种名为 OneRec 的统一生成式推荐框架,旨在替代传统的多阶段排序策略,通过一个端到端的生成模型直接生成推荐结果。OneRec 的主要贡献包括: 编码器-解码器结构:采用稀疏混合专家(MoE)架构…...
AVL树的平衡算法的简化问题
AVL树是一种紧凑的二叉查找树。它的每个结点,都有左右子树高度相等,或者只相差1这样的特性。文章https://blog.csdn.net/aaasssdddd96/article/details/106291144给出了一个例子。 为了便于讨论,这里对AVL树的结点平衡情况定义2个名称&#…...
mac安装navicat及使用
0.删除旧的 sudo rm -Rf /Applications/Navicat\ Premium.app sudo rm -Rf /private/var/db/BootCaches/CB6F12B3-2C14-461E-B5A7-A8621B7FF130/app.com.prect.NavicatPremium.playlist sudo rm -Rf ~/Library/Caches/com.apple.helpd/SDMHelpData/Other/English/HelpSDMIndexF…...
【HTML】二、列表、表格
文章目录 1、列表1.1 无序列表1.2 有序列表1.3 定义列表 2、表格2.1 定义2.2 表格结构标签2.3 合并单元格 1、列表 列表分为: 无序列表有序列表定义列表:一个标题下有多个小分类 1.1 无序列表 ul嵌套li,ul是无序列表,li是列表…...
大语言模型安全风险分析及相关解决方案
大语言模型的安全风险可以从多个维度进行分类。 从输入输出的角度来看,存在提示注入、不安全输出处理、恶意内容生成和幻觉错误等风险; 从数据层面来看,训练数据中毒、敏感信息泄露和模型反演攻击是主要威胁; 模型自身则面临拒绝服务和盗窃的风险; 供应链和插件的不安全引…...
windows平台的ffmpeg编译使用
windows平台的ffmpeg编译使用 一、现状 本人使用libgdx开发galGame,发现扩展包gdx-video不支持mp4,不能忍,正好看到官网有支持自定义编译的文档,所以操作一下,自定义编译。本文重点在于操作windows平台,linux平台太简单了。 整个过程包括如下几个步骤。 二、代码下载…...
FFMPEG录制远程监控摄像头MP4
手绘效果图 上图是录制功能的HTML前端页面,录制功能和解码视频放在一起。录制功能关键是录制(开始录制按钮)、停止录像按钮。当点击“录制”的时候则会开始录制MP4文件, 当点击停止的时候就会停止录制MP4。经过录制后,则会生成MP4,并放到我的RV1126的/tm…...
centos操作系统上传和下载百度网盘内容
探序基因 整理 进入百度网盘官网百度网盘 客户端下载 下载linux的rpm格式的安装包 在linux命令行中输入:rpm -ivh baidunetdisk_4.17.7_x86_64.rpm 出现报错: 错误:依赖检测失败: libXScrnSaver 被 baidunetdisk-4.17.7-1.x8…...
Rubick:基于 Electron 的开源插件化桌面效率工具箱
Rubick 是一款基于 Electron 构建的开源桌面工具箱,专为追求高效办公和个性化体验的用户设计。它通过自由集成丰富的插件,让用户能够根据自己的需求打造极致的桌面端效率工具。 软件命名由来Rubick 的名字来源于《DOTA2》中的英雄 Rubick(拉…...
ruoyi-vue部署
ruoyi源码类型 Ruoyi源码 编译打包后,直接部署tomcat服务器 Ruoyi-vue 前后端分离版 前端部署到nginx 后端部署到tomcat RuoYi-Cloud 微服务版 RuoYi-app 移动端版 RuoYi-vue 前后端分离版 环境 JDK>=1.8 MySQL >= 5.7 Maven >= 3.0 Node >= 12 Redis…...
MyBatis 如何创建 SqlSession 对象的?
MyBatis 创建 SqlSession 对象的过程主要由 SqlSessionFactory 接口及其实现类来完成。以下是详细步骤: 1. SqlSessionFactory 接口: SqlSessionFactory 是 MyBatis 的核心接口之一,它负责创建 SqlSession 对象。 你可以将 SqlSessionFactory 视为 Sql…...
LLM论文笔记 23: Meta Reasoning for Large Language Models
Arxiv日期:2024.6.17机构:THU / MSRA 关键词 meta-reasoning推理方法prompt engineering 核心结论 1. 提出Meta Reasoning prompting,MRP是一种系统提示方法,能够帮助LLM动态选择最合适的推理方法,从而提升其灵活性和…...
【最后203篇系列】015 几种消息队列的思考
背景 队列还是非常重要的中间件,可以帮助我们:提高处理效率、完成更复杂的处理流程 最初,我觉得只要掌握一种消息队列就够了,现在想想挺好笑的。 过去的探索 因为我用python,而rabbitmq比较贴合快速和复杂的数据处…...
golang time包和日期函数
1.简介 在程序中日期和时间是我们经常会用到的,在go中time包提供了时间的显示和测量函数。 2.获取当前时间 通过time.Now()函数获取当前时间对象,然后获取时间对象的年月日时分秒等值。 now : time.Now()fmt.Printf("now%v type%T\n", now…...
学习springboot 的自动配置原理
前言 为什么要学习springboot 的自动配置原理? 1学习 自定义成starter 的前提 实际开发中,我们如果定义公共的组件给团队使用,为了让他们使用方便就自定义成starter。而想要学习starter ,就要先了解springboot 的自动配置原理 2 面试需要 了…...
排错 -- FISCO BCOS区块链网络 -- 3. 编译智能合约
文章为FISCO BCOS2.0搭建区块链平台中发现的问题与总结,出错原因不唯一 ,解决办法不唯一 目前社区缺少完整,稳定的搭建平台和教程 ,欢迎各位及时补充,如有错误请及时评论纠正! 感谢各位搜索到这里&#…...
ffmpeg 添加毫秒时间戳
网上有好多添加时间水印的,默认是到秒,而我需要到毫秒,查了一下,没有找到更好的方案,下面是自己实现的方案,可以显示到毫秒。如果有更好的方案,欢迎讨论 ffmpeg -i video.mp4 -vf "drawte…...
centos7上安装Docker
文章目录 **1. 使用华为云镜像源替换Docker仓库****2. 安装Docker CE****3.更换docker镜像源-使用华为云的docker镜像源****4.补充:docker的使用****5.补充:删除docker的步骤** 1. 使用华为云镜像源替换Docker仓库 步骤: 删除无效的Docker仓…...
