使用模板工厂模式实现动态创建C++对象

一、前言

在现代C++开发中,工厂模式是常见的设计模式之一,能够有效地解耦对象创建与使用代码。本文介绍一个模板类 ComponentsFactory,它运用了模板编程和工厂模式,实现了一种动态的对象创建方式。通过该工厂,我们可以基于类的描述信息在运行时注册并生成对象,而无需直接依赖具体类。这种设计在需要动态扩展组件或模块的系统中非常实用。

二、什么是模板工厂模式

在C++中,工厂模式(Factory Pattern)通常用于创建复杂的对象实例,将对象的创建与使用解耦。而模板工厂模式在工厂模式的基础上引入了模板编程,以支持类型的多样性。本文中的 ComponentsFactory 便是一个模板工厂类,它能根据注册的类名信息来创建对应类型的对象。

二、 ComponentsFactory 的设计概述

我们定义一个模板类 ComponentsFactory,其中包含了一组静态方法,负责将类型 C 的子类动态注册并创建。下面,我们通过 ComponentsFactory 的代码分步进行功能说明。

template<typename C>
class ComponentsFactory {

这个类模板 ComponentsFactory 接收一个类型参数 C,它是工厂的基类或接口类型。工厂将创建的对象必须继承自 C,使得我们能够通过多态来操作这些对象。

三、实现方法详解

3.1 注册类型:registerClass

registerClass 方法用于将类型 T 注册到工厂中。注册时需要提供一个 ComponentsDesc 类型的对象,该对象包含类的描述信息(如类名等)。

template<typename T>
static void registerClass(const ComponentsDesc& registerComponent) {constructors().insert(registerComponent, &constructorHelper<T>);
}

在这个方法中:

  • registerComponent 是 ComponentsDesc 类型的类描述信息,用于识别类。
  • constructors() 是一个哈希表,存储了类描述信息和对应的构造函数指针。
  • constructorHelper 是一个构造辅助函数,负责创建具体类型 T 的对象实例。

3.2 基于类名动态创建对象:create

create 方法根据提供的类名(registerComponent)来创建对象实例。它首先在 constructors 中查找匹配的构造函数指针,然后调用该指针来创建对象。

static C* create(const QByteArray& registerComponent, bool realTrade, C* parent = nullptr) {Constructor constructor = nullptr;QString tooltip;QList<ComponentsDesc> descs = keys();foreach (ComponentsDesc var, descs) {if(var.className == registerComponent){constructor = constructors().value(var);tooltip = var.componentsName;break;}}if (constructor == nullptr)return nullptr;C* obj = (*constructor)(realTrade, parent);if(obj) {obj->setProperty("className", registerComponent);obj->setProperty("toopTip", tooltip);}return obj;
}

该方法的主要流程:

  1. 遍历 constructors,查找与 registerComponent 匹配的构造函数。
  2. 找到构造函数后,调用它创建对象。
  3. 若未找到对应的构造函数,则返回 nullptr。
  4. 如果对象创建成功,将 className 和 toopTip 属性设置到对象上。
  5. 这个方法确保了对象的创建逻辑与使用代码分离,使得系统可以动态加载新类型。

3.3 使用完整的描述信息创建实例:createByWholeInfo

createByWholeInfo 方法与 create 类似,不同的是它使用一个 ComponentsDesc 对象作为参数,从而在创建对象时可以利用完整的类描述信息。

static C* createByWholeInfo(const ComponentsDesc& registerComponent, bool realTrade, C* parent = nullptr) {Constructor constructor = constructors().value(registerComponent);if (constructor == nullptr)return nullptr;C* obj = (*constructor)(realTrade, parent);if (obj) obj->setProperty("className", registerComponent.className);return obj;
}

这为创建提供了更大的灵活性,例如在需要为特定类设置更多属性时非常有用。

3.4 查看已注册的类信息:keys

keys 方法返回所有已注册的 ComponentsDesc 列表,方便查询和调试。

static QList<ComponentsDesc> keys() { return constructors().keys(); }

3.5 私有成员:构造函数指针和辅助函数

私有成员包括:

  • 构造函数指针类型 Constructor。
  • constructorHelper 函数,它是一个模板函数,用于具体创建对象。
typedef C* (*Constructor)(bool realTrade, C* parent);template<typename T>
static C* constructorHelper(bool realTrade, C* parent) {return new T(realTrade, parent);
}

3.6 存储类和构造函数的映射:constructors

constructors 返回一个静态哈希表,它将类描述信息与构造函数指针关联起来。

static QHash<ComponentsDesc, Constructor>& constructors() {static QHash<ComponentsDesc, Constructor> instance;return instance;
}

四、代码总结

ComponentsFactory 通过模板工厂模式实现了动态创建对象的能力。它的核心功能包括:

  • 使用 registerClass 注册不同类型的类,使得工厂可以动态扩展支持的类型。
  • 通过 create 和 createByWholeInfo 方法实现动态对象创建,避免硬编码类类型。
  • 提供 keys 方法查询注册信息,使得工厂状态透明可查。
  • 这种设计为系统的扩展性和维护性提供了极大的便利,是一种优雅的工厂模式实现方式。

五、应用场景

这个模板工厂可以用于:

  • 插件系统:根据类描述动态加载和创建插件对象。
  • 组件管理:在需要灵活添加、移除或更改组件的系统中。
  • 依赖注入:将创建逻辑从业务逻辑中解耦,特别适用于复杂系统的初始化。
  • 通过这种工厂模式,不仅提升了代码的灵活性,也大大降低了系统的耦合度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/58875.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux_04 Linux常用命令——tar

一、命令格式 tar [选项] [归档文件] [要处理的文件或目录]1、选项 c创建归档文件x解压缩归档文件z使用gzipj使用bzip2v处理过程显示信息f指定归档文件名称 2、归档文件-可指定目录及文件名 /home/wang.tar.gz 3、要处理的文件或目录 /home/study1/wang 二、常见命令 t…

【1个月速成Java】基于Android平台开发个人记账app学习日记——第一天

24.10.31 开发前准备 IDE下载与配置GitHub仓库创建 IDE下载与配置 下载最新版本IDEA&#xff0c;卸载之前的旧版本 后面一路跟着安装的默认选项走即可 安装完以后这个最新的可以把我再jetbrains的其他软件设置导入&#xff0c;很方便 接下来创建新的项目并进行安卓应用开发…

【elkb】索引生命周期管理

索引生命周期管理 Index lifecycle management(索引生命周期管理)是elasticsearch提供的一种用于自动管理索引的生命周期的功能。允许使用者定义索引的各个阶段&#xff0c;从创建至删除。并允许使用者在每个阶段定义索引需要执行的特定动作。这些动作包含索引创建&#xff0c…

HttpServer模块 --- 封装TcpServer支持Http协议

目录 模块设计思想 模块代码实现 模块设计思想 本模块就是设计一个HttpServer模块&#xff0c;提供便携的搭建http协议的服务器的方法。 那么这个模块需要如何设计呢&#xff1f; 这还需要从Http请求说起。 首先http请求是分为静态资源请求和功能性请求的。 静态资源请求…

外接数据库给streamlit等web APP带来的变化

之前我采用sreamlit制作了一个调查问卷的APP&#xff0c; 又使用MongoDB作为外部数据存储&#xff0c;隐约觉得外部数据库对于web APP具有多方面的意义&#xff0c;代表了web APP发展的趋势之一&#xff0c;似乎是作为对这种趋势的响应&#xff0c;streamlit官方近期开发了st.c…

sql题库中常见问答

一.解答题 (15*2) 1 Drop, delete,truncates 三者的区别? ①、drop和truncate属于数据库的定义语言(DDL) ②、delete属于数据库的操作语言(DML) ③、drop可以删除全表结果,且删除的同时会删除表数据 ④、delete 和truncate只能删除表数据,truncate会删除表数据一起…

黄山谷捷IPO拟募资5亿元,增强核心竞争力

根据深交所发行上市审核进度&#xff0c;10月28日&#xff0c;黄山谷捷股份有限公司首发申请审核状态变更为“提交注册”。据悉&#xff0c;黄山谷捷本次拟公开发行不超过2,000万股&#xff0c;占本次发行后总股本的比例不低于25.00%。 招股书&#xff08;注册稿&#xff09;披…

无人机拦截捕获/直接摧毁算法详解!

一、无人机拦截捕获算法 网捕技术 原理&#xff1a;抛撒特殊设计的网具&#xff0c;捕获并固定无人机。 特点&#xff1a; 适用于小型无人机。 对无人机的损害较小&#xff0c;基本不影响其后续使用。 捕获成功率较高&#xff0c;且成本相对较低。 应用实例&#xff1a;…

.NET Core WebApi第4讲:控制器、路由

一、控制器是什么&#xff1f; 1、创建一个空的API控制器&#xff1a;TestController.cs 2、里面有一个类叫TestController&#xff0c;把它叫做控制器 因为它继承了ControllerBase类&#xff0c;ControllerBase类里提供了一系列的方法&#xff0c;使得TestController这个类具…

WAF+AI结合,雷池社区版的强大防守能力

网上攻击无处不不在&#xff0c;为了保护我自己的网站&#xff0c;搜索安装了一个开源免费的WAF 刚安装完成就收到了海外的攻击&#xff0c;看到是海外的自动化攻击工具做的 雷池刚好也有AI分析&#xff0c;于是就尝试使用这个功能&#xff0c;看看这个ai能力到底怎么样 以下…

Python批量查找包含多个关键词的PDF文件

在信息爆炸的时代&#xff0c;数据管理变得愈发重要。U盘作为一种便携式存储设备&#xff0c;常常承载着我们大量的个人和工作数据。然而&#xff0c;随着文件数量的增加&#xff0c;在U盘中快速找到特定文件常常成为一个令人头疼的难题。我们通常可以采用everything来快速查找…

Chromium HTML5 新的 Input 类型tel对应c++

一、Input 类型: tel <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>test</title> </head> <body><form action"demo-form.php">电话号码: <input type"tel" name…

cisco网络安全技术第4章测试及考试

测试 以下 ACE 将放置在何处&#xff1f; permit icmp any any nd-na 试题 1选择一项&#xff1a; 在连接到另一个路由器并已启用 IPv6 的路由器接口上 使用下一代防火墙而不是状态防火墙的一个好处是什么&#xff1f; 试题 2选择一项&#xff1a; 主动而不是被动防护互…

【SQL】SQL函数

&#x1f4e2; 前言 函数 是指一段可以直接被另一段程序调用的程序或代码。主要包括了以下4中类型的函数。 字符串函数数值函数日期函数流程函数 &#x1f384; 字符串函数 ⭐ 常用函数 函数 功能 CONCAT(S1,S2,...Sn) 字符串拼接&#xff0c;将S1&#xff0c;S2&#xff0…

Springboot 整合 Java DL4J 构建自然语言处理之机器翻译系统

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

第三份代码:VoxelNet的pytorch实现

VoxelNet是点云体素化处理的最开始的网络结构设计&#xff0c;通过完全弄明白整个VoxelNet的pytorch实现是非常有必要的。 参考的代码是这一份&#xff1a;GitHub - RPFey/voxelnet_pytorch: modification of voxelnet 参考文章&#xff1a;VoxelNet论文解读和代码解析_voxel…

vue3-element-admin 去掉登录

1.src/router/index 去掉登录路由 // {// path: "/login",// component: () > import("/views/login/index.vue"),// meta: { hidden: true },// },2./src/plugins/permission修改 未登录 import type {NavigationGuardNext,RouteLocationNormal…

CentOS 9 Stream 上安装 Redis

CentOS 9 Stream 上安装 Redis CentOS 9 Stream 上安装 RedisCentOS 9 Stream 上卸载 Redis CentOS 9 Stream 上安装 Redis 在 CentOS 9 Stream 上安装 Redis&#xff0c;可以按照以下步骤进行&#xff1a; 更新系统包&#xff1a; sudo dnf update -y安装 Redis&#xff1a; …

NLP算法工程师精进之路:顶会论文研读精华

1.学术能力培养 全部论文资料下载&#xff1a; 将论文和 GitHub 资源库匹配 papers with code https://paperswithcode.com/OpenGitHub 新项目快报Github pwc&#xff1a;https://github.com/zziz/pwc GitXiv&#xff1a;http://www.gitxiv.com/ 文章撰写 Overleaf [Autho…

01_AI编程案例展示:借助AI轻松爬取海量网盘链接

爬虫案例展示 今天,我们将展示如何利用AI快速开发一个网络爬虫&#xff0c; 使用的工具是Python和Claude 3.5 Sonnet(国内可用豆包替代) 我们的目标是爬取panhub.fun网站上的夸克网盘链接, 即使你是编程新手,也可以轻松完成这样的任务。 案例1-批量爬取panhub网盘整合包 下…