使用模板工厂模式实现动态创建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.xdnf.cn/news/3746.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

《2024中国城市音乐产业发展指数报告》重磅发布

11月4日,《2024中国城市音乐产业发展指数研究报告》(以下简称“报告”)在成都首次公开发布。该报告由中国音像与数字出版协会音乐产业促进工作委员会指导编制,道略产业研究院、四川音乐学院孙洪斌教授团队深度参与。 该指数评价对象涵盖直辖市、副省级城市和省会城市等共36个城…

解锁金融未来,Python带你玩转大数据!

厌倦了复杂的金融报表&#xff0c;想用数据驱动投资决策&#xff0c;却不知从何下手&#xff1f; 别担心&#xff01; 《Python金融大数据分析快速入门与案例详解》带你轻松入门&#xff0c;掌握数据分析利器&#xff0c;成为金融领域的弄潮儿&#xff01; 为什么选择这本书&…

STM32 + CubeMX + 硬件SPI + W5500 +TcpClient

这篇文章记录一下STM32W5500TCP_Client的调试过程&#xff0c;实现TCP客户端数据的接收与发送。 目录 一、W5500模块介绍二、Stm32CubeMx配置三、Keil代码编写1、添加W5500驱动代码到工程&#xff08;添加方法不赘述&#xff0c;驱动代码可以在官网找&#xff09;2、在工程中增…

template advanced

一.仿函数再探 stl_stack/queue-CSDN博客 在priority_queue中&#xff0c;我们介绍了仿函数作为第三个参数来改变堆的类型&#xff0c;而仿函数还有其他的用处。 那么我们是否可以借助优先级队列来对日期类进行排序呢&#xff1f; 答案是可以的&#xff0c;但前提是该日期…

spring源码[spring启动流程]

spring启动流程 AnnotationConfigApplicationContext的构造方法 1.父类构造方法&#xff0c;构造一个DefaultListableBeanFactory 在调用AnnotationConfigApplicationContext的构造方法之前&#xff0c;会调用父类GenericApplicationContext的无参构造方法&#xff0c;会构造…

使用Python做一个微信机器人

使用Python制作微信机器人是一个有趣且实用的项目&#xff0c;它可以让您自动化处理微信消息、监控微信群、甚至实现智能聊天等功能。 请求参数 Header 参数 export interface ApifoxModel {"X-GEWE-TOKEN": string;[property: string]: any; } Body 参数applicat…

Python-创建并调用自定义文件中的模块/函数

背景&#xff1a;在Python编程中&#xff0c;我们常常需要创建自己的专属文件&#xff0c;以便帮助我们更高效&#xff0c;快捷地完成任务。那么在Python中我们怎么创建并调用自己文件中的模块/函数呢? 在Python中调用自定义文件&#xff0c;通常是指调用自己编写的Python模块…

【C++】C++17结构化绑定、std::optional、std::variant、std::any

二十二、C17中的结构化绑定、std::optional、std::variant、std::any 本部分是一个小系列&#xff0c;介绍C17中新引入的、用来解决各种不同返回情况的、标准库新组件。 1、C的结构化绑定 结构化绑定structured bindings是C17中引入的一项特性&#xff0c;它允许开发者方便地…

ntkrnlmp.exe导致蓝屏死机的解决方法

在使用Windows操作系统的过程中&#xff0c;用户可能会遇到由ntkrnlmp.exe文件错误引发的蓝屏死机&#xff08;Blue Screen of Death, BSOD&#xff09;问题&#xff0c;这不仅影响了日常的工作效率&#xff0c;也可能造成数据丢失的风险。本文将为您提供一系列即时排查与修复n…

U3D游戏开发之骨骼动画相关

目录 1 作为U3D程序如何制作骨骼动画 2 骨骼动画程序代码相关 这个内容我在很久之前就想写了&#xff0c;很多项目也与骨骼动画挂钩&#xff0c;今天我们揭秘的是2D骨骼动画。来聊一聊大家可能非常关注的两个问题&#xff1a;作为程序如何制作骨骼动画&#xff1f;接到美术的骨…

java:题目:用Java实现简单的自取取款操作

import java.util.Scanner; public class ATM {public static void main(String[] args){//自主取款主类Scanner scnew Scanner(System.in);System.out.println("请输入账户号码&#xff1a;");String BankAccoutsrsc.nextLine();/BankAccout3 newBankAccoutnew Bank…

VLAN 高级技术 ——QinQ的配置

QinQ的概述&#xff1a; QinQ技术是一种扩展虚拟局域网&#xff08;VLAN&#xff09;数量空间的技术&#xff0c;通过在802.1Q标签报文的基础上再增加一层802.1Q的Tag来实现。以下是对QinQ技术的详细概述&#xff1a; QinQ技术的定义与背景 定义&#xff1a;QinQ&#xff08…

不得不承认供电公司信息宣传向媒体投稿的好方法找到了

初入国网供电公司,我被分配到了信息宣传部门,负责每月的信息宣传投稿任务。这项任务看似简单,实则充满挑战。一开始,我满怀热情,以为只要写出高质量的文章,就能顺利发表。然而,现实给了我当头一棒。传统的邮箱投稿方式,不仅竞争压力大,审核严格,而且周期漫长。每次投稿后,我总是…

『YOLOV5』| 一文搞定训练过程中的意外终止、以及想继续增加训练轮数!

文章目录 情况一&#xff1a;意外训练中断&#xff08;程序未训练完成&#xff0c;想完成目标训练轮数&#xff09;情况二&#xff1a;自动训练完成&#xff08;程序已完成训练&#xff0c;想增加训练轮数&#xff09; 情况一&#xff1a;意外训练中断&#xff08;程序未训练完…

GCC编译器的`-Wall`、`-Wextra`和`-pedantic`选项解读

gcc是广泛使用的开源编译器&#xff0c;-Wall、-Wextra和-pedantic是gcc中用于控制警告信息的选项&#xff0c;以下是详细介绍&#xff1a; -Wall&#xff08;启用大部分警告&#xff09; 功能&#xff1a;-Wall 选项用于启用一系列常用的警告信息&#xff0c;这些警告能帮助…

MMBench-Video:上海 AI Lab 联合多所高校推出长视频理解基准测试工具,全面评估 LVLMs 视频理解的能力

❤️ 如果你也关注大模型与 AI 的发展现状&#xff0c;且对大模型应用开发非常感兴趣&#xff0c;我会快速跟你分享最新的感兴趣的 AI 应用和热点信息&#xff0c;也会不定期分享自己的想法和开源实例&#xff0c;欢迎关注我哦&#xff01; &#x1f966; 微信公众号&#xff…

高频电子线路---调角频谱与频宽

目录 调角频谱(FM单频调制) 带宽 调频方法 直接调频方法与电路 变容二极管 如何提升频偏? 1. 增大调制信号的幅度&#xff08;增大调制深度&#xff09; 2. 提高调制信号的频率 3. 提高调制深度&#xff08;调制指数&#xff09; 4. 增加发射功率 5. 使用特殊的调制…

摘要、数字签名、对称加密、非对称加密综合应用示例以及技术原理说明

图&#xff1a;介绍了数字信封的安全传输过程 关键术语 散列&#xff1a;Hash&#xff08;哈希&#xff09;&#xff0c;一般翻译做散列、杂凑&#xff0c;是把任意长度的输入&#xff08;数据信息&#xff09;通过散列算法变换成固定长度的输出&#xff0c;该输出就是散列值…

java学习3---面向对象

一、设计对象并使用 1.类和对象 类是共同特征的描述&#xff1b;对象是真实存在的具体实例。 2.类的几个补充注意事项 二、封装 对象代表什么&#xff0c;就得封装对应的数据&#xff0c;并提供数据对应的行为。 封装告诉我们如何正确的设计对象 三、this关键字 this可以区…

Maven

Maven 命令方式构建项目 mvn compile&#xff1a;编译项目&#xff0c;生成target文件&#xff08;不编译测试代码&#xff09; mvn package&#xff1a;打包项目&#xff0c;生成jar或war文件&#xff08;不指定默认jar包&#xff09; mvn clean&#xff1a;清理编译或打包后…