工厂模式——工厂方法模式+注册表

工厂方法模式的瑕疵

前一篇笔记中我们介绍了工厂方法模式,示例的类图如下:

考虑一种情况:现在要在程序运行时,根据外部资源,动态的实例化对象。也就是说在编译期我们无法知道要实例化的对象的类型。因此在实例化的过程中,就需要加以判断。

例如,在我的例子中,要根据连接到主机的相机来实例化相机对象,那么客户端(使用工厂方法创建实例的一方)使用工厂方法模式创建对象的时候,代码可能是这样:

//运行时确定数组大小,且确定后不可改变
auto camera_devices_ = std::make_unique<std::shared_ptr<CameraDevice>[]>(onlined_camera_num_);for(int i = 0; i < onlined_camera_num_; ++i)
{std::shared_ptr<CameraDeviceFactory> factory;if("Sick" == camera_name[i])    //camera_name[i]中元素是提前获取的与连接的相机对应的供应商名称factory = std::make_shared<SickCameraFactory>();else if("Basler" == camera_name[i])factory = std::make_shared<BaslerCameraFactory>();else if("Huaray" == camera_name[i])factory = std::make_shared<HuarayCameraFactory>();camera_devices_[i] = factory->CreateCamera();
}

虽然工厂方法模式遵循了开闭原则,即当有新类型的时候,无需修改现有的代码,只需新加产品类和对应工厂类即可。但是对于客户端来说,当需要实例化的类型数量增加时,就需要新增else if去适配,这使得客户端代码变得冗长且难以维护。

注册表

为了解决上面问题,我们可以实现一个类型的注册表,允许动态创建对象。这种方法通过将关键字映射到构造函数指针,使得可以根据字符串名称动态地实例化对象。

#ifndef Reflection_H
#define Reflection_H#include <map>
#include <string>template <typename T, typename... ArgType>
void* CreateInstance(ArgType... args)
{return new T(args...);
}//需要反射的类使用该宏注册
#ifndef ReflectRegister
#define ReflectRegister(identifier, class_name, ...) \static bool __type##class_name = Object::Register(identifier, (void*)CreateInstance<class_name, ##__VA_ARGS__>);
#endifclass Object
{
public:template <typename BaseClass, typename... ArgType>static BaseClass *CreateObject(const std::string &vendor_name, ArgType... args){using CreateFactory = BaseClass *(*)(ArgType...);auto& class_map = GetStaticFuncMap();auto iter = class_map.find(vendor_name);if (iter == class_map.end()){CRRC_ERROR("class_name not found in map");return nullptr;}else{CRRC_DEBUG("class_name found in map");return reinterpret_cast<CreateFactory>(class_map[vendor_name])(args...);}} //向map中注册关键字和类的构造函数static bool Register(const std::string &vendor_name, void *ctor_ptr){CRRC_DEBUG("Register class_name:"<<vendor_name);GetStaticFuncMap()[vendor_name] = ctor_ptr;return true;}private://获取全局唯一的map//map记录了关键字和类的构造函数的映射关系static std::map<std::string, void*>& GetStaticFuncMap(){static std::map<std::string, void*> class_map_;return class_map_;}};#endif //Reflection_H

在具体相机工厂中,我们可以使用ReflectRegister注册此类(以Basler相机为例,其余类似):

class BaslerCameraDeviceFactory : public CameraDeviceFactory
{
public:std::shared_ptr<CameraDevice> CreateCameraDevice() override{return std::make_shared<BaslerCameraDevice>();}
};ReflectRegister("Basler", BaslerCameraDeviceFactory);

好了,现在回头再看客户端使用工厂方法模式创建对象的代码,就可以简化为:

//运行时确定数组大小,且确定后不可改变
auto camera_devices_ = std::make_unique<std::shared_ptr<CameraDevice>[]>(onlined_camera_num_);for(int i = 0; i < onlined_camera_num_; ++i)
{auto p_factory = Object::CreateObject<CameraDeviceFactory>(camera_name[i]);//camera_name[i]中元素是提前获取的与连接的相机对应的供应商名称if (!p_factory)continue;elsecamera_devices_[i] = p_factory->CreateCameraDevice();delete p_factory;
}

文章转载自:paw5zx

原文链接:https://www.cnblogs.com/paw5zx/p/18229334

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

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

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

相关文章

Java 新手入门:基础知识点一览

Java 新手入门&#xff1a;基础知识点一览 想要踏入 Java 的编程世界&#xff1f;别担心&#xff0c;这篇文章将用简单易懂的表格形式&#xff0c;带你快速了解 Java 的基础知识点。 一、Java 是什么&#xff1f; 概念解释Java一种面向对象的编程语言&#xff0c;拥有跨平台、…

JDBC-MySQL

JDBC-MySQL 1.JDBC 操作步骤1.1 DriverManager1.2.Connection对象1.3 Statement1.4 PreparedStatement 1.JDBC 操作步骤 public void quickStart() throws ClassNotFoundException, SQLException {//1、注册驱动 &#xff08;确认要使用哪个数据库&#xff09;Class.forName(&…

短视频直播教学课程小程序的作用是什么

只要短视频/直播做的好&#xff0c;营收通常都不在话下&#xff0c;近些年&#xff0c;线上自媒体行业热度非常高&#xff0c;每条细分赛道都有着博主/账号&#xff0c;其各种优势条件下也吸引着其他普通人冲入。 然无论老玩家还是新玩家&#xff0c;面对平台不断变化的规则和…

《2024年DDoS趋势报告》:DDoS攻击规模飙升233.33%

2023年&#xff0c;数字领域面临着分布式拒绝服务&#xff08;DDoS&#xff09;攻击的变革浪潮&#xff0c;攻击速度创纪录地达到了每秒700 Gbps和8000万数据包。这些事件跨越了从游戏到金融服务的各个行业&#xff0c;突显了DDoS是一种普遍存在的风险。 值得注意的是&#xf…

Ubuntu server 24 (Linux) sudo 免输密码

1 sudo 使用要输入密码&#xff0c;费时费力。 2 sudo命令免输密码&#xff0c;需要修改/etc/sudoers文件 #本文以test用户为例,#允许不需要输入密码执行 sudo vi /etc/sudoers test ALL(ALL) NOPASSWD: ALL %sudo ALL(ALL:ALL) ALL --> #%sudo ALL(ALL:ALL) ALL#所有…

掌握 NestJS 10.x:NestJS 结合 PostgreSQL 使用详解

NestJS 是一个用于构建高效、可扩展的 Node.js 服务端应用的框架。结合 PostgreSQL 数据库,可以为应用提供强大的数据存储和查询功能。本文将详细介绍如何在 NestJS 项目中集成和使用 PostgreSQL,并创建一个包含增加用户接口的完整示例。 1. 安装必要的依赖 首先,确保你的…

基于VITA57.4标准的单通道6GSPS 12位采样ADC,单通道 6GSPS 16位采样DAC子卡模块

板卡概述 FMC147是一款单通道6.4GSPS&#xff08;或者配置成2通道3.2GSPS&#xff09;采样率的12位AD采集、单通道6GSPS&#xff08;或配置成2通道3GSPS&#xff09;采样率16位DA输出子卡模块&#xff0c;该板卡为FMC标准&#xff0c;符合VITA57.4规范&#xff0c;该模块可以作…

Day 42 LVS四层负载均衡

一&#xff1a;负载均衡简介 1.集群是什么 ​ 集群&#xff08;cluster&#xff09;技术是一种较新的技术&#xff0c;通过集群技术&#xff0c;可以在付出较低成本的情况下获得在性能、可靠性、灵活性方面的相对较高的收益&#xff0c;其任务调度则是集群系统中的核心技术 …

量化研究---大qmt实盘实现禄得可转债策略轮动

前面写了一个强大的可转债自定义系统&#xff0c;我们可以利用这个快速对接到大qmt,我提供实时数据支持 量化研究---强大的可转债分析系统上线&#xff0c;提供api&#xff0c;实时数据支持 打开网页 http://120.78.132.143:8023/ 强大可转债选择系统 http://120.78.132.143:8…

容器中运行ifconfig提示bash: ifconfig: command not found【笔记】

容器中运行ifconfig提示bash: ifconfig: command not found 这个问题是因为在容器中没有安装ifconfig命令。 在容器中安装ifconfig命令&#xff0c;可以使用以下命令&#xff1a; 对于基于Debian/Ubuntu的容器&#xff0c;使用以下命令&#xff1a; apt-get update apt-get …

每日一练:利用多态思想和ArrayList集合,编写一个模拟KTV点歌系统的程序。【多态思想和ArrayList集合的综合应用】

目录 一、设计程序使用ArrayList集合&#xff0c;编写一个模拟KTV点歌系统的程序。参考代码歌曲类歌单类KTV类测试类运行效果 总结 最后 一、设计程序 使用ArrayList集合&#xff0c;编写一个模拟KTV点歌系统的程序。 要求&#xff1a; 输入0代表添加歌曲输入1代表将所选歌曲…

云原生环境下GPU算力调度发展分析

云原生环境下GPU算力调度深度分析 概述&#xff1a; 云原生时代&#xff0c;GPU算力调度与管理备受瞩目&#xff0c;成为企业和云服务提供商关注的焦点&#xff0c;助力AI、深度学习、高性能计算等领域&#xff0c;满足对GPU资源的迫切需求。 容器化与编排&#xff1a; Kube…

突破开源天花板!最强文本转语音工具ChatTTS:对话式高可控的语音合成模型

ChatTTS 一夜爆火&#xff0c; 极速出圈&#xff0c; 3 天就斩获 9k 的 Star 量&#xff0c; 截止 2024.06.04&#xff0c; 已经 19.3k 的 star&#xff0c; 极速接近 GPT-soVITs 当天的 26.2k 的 star 数。 什么是ChatTTS&#xff1f; TTS全称&#xff1a;Text To Speech&am…

数字生命计划1.0

一. 背景 即使人们强调思维与肉体是两大构成个体的先决条件&#xff0c;但科学界始终没有放弃探索摆脱肉体的介质&#xff0c;从而让思维上载的研究。 这就是数字生命计划的初衷。所谓数字生命&#xff0c;就是将人类的意识思维抽离&#xff0c;上传至云端或智能终端&#xf…

eMMC的封装类型及特点有哪些?

eMMC&#xff08;Embedded MultiMediaCard&#xff09;是一种高度集成的嵌入式存储解决方案&#xff0c;广泛应用于智能手机、平板电脑、笔记本电脑、消费电子产品和物联网设备等领域。eMMC的封装形式对其性能、应用和设备设计有着重要的影响。目前&#xff0c;eMMC主要有两种封…

航空航天技术翻译要求

航空航天技术是一项国际化产业&#xff0c;航空技术更新迅速涉及的专业知识较为广泛。在航空领域&#xff0c;每一个术语都有着特定的含义和用法&#xff0c;稍有差池就可能导致翻译出现严重的后果&#xff0c;因此&#xff0c;航空航天翻译扮演者至关重要的角色。 专业航空航天…

【ARM Cache 与 MMU 系列文章 7.6 -- ARMv8 MMU 相关寄存器介绍】

文章目录 MMU 转换控制寄存器 TCR_ELxTCR_ELx 概览TCR_ELx 寄存器字段详解TCR 使用示例Normal MemoryCacheableShareability MMU 内存属性寄存器 MAIR_ELx寄存器结构内存属性字段使用实例 MMU 地址翻译表基址寄存器 TTBR0/1_ELxTTBR0_ELx 寄存器概述寄存器结构功能和用途编程示…

idea Pycharm Webstorm 2024年 最新版 永久使用2099年教程 附激活码亲测可用

idea Pycharm Webstorm 2024年 最新版 永久使用2099年教程 附激活码亲测可用 链接&#xff1a; 下载 IntelliJ IDEA – 领先的 Java 和 Kotlin IDE (jetbrains.com)&#xff08;这是官网的&#xff09; 下载 安装 1.双击idea的安装包&#xff0c;点击next 选择创建桌面快捷…

深入剖析时序Prophet模型:工作原理与源码解析|得物技术

随着得物业务的快速发展&#xff0c;积累了大量的时序数据&#xff0c;这些数据对精细化运营&#xff0c;提升效率、降低成本有着重要作用。在得物的时序数据挖掘场景中&#xff0c;时序预测Prophet模型使用频繁&#xff0c;本文对Prophet的原理和源码进行深入分析&#xff0c;…

边缘计算网关:企业数字化转型的重要支撑-天拓四方

在数字化浪潮席卷全球的今天&#xff0c;企业对于数据处理和传输的需求日益增强。然而&#xff0c;传统的数据处理模式往往依赖于中心化的数据中心&#xff0c;这种方式在处理大量数据时存在延迟高、成本高、安全性差等问题。数据量的激增和实时性要求的提高&#xff0c;使得传…