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

工厂方法模式的瑕疵

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

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

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

//运行时确定数组大小,且确定后不可改变
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;拥有跨平台、…

男人只需布局三年,就没人敢瞧不起你

一、每天布局&#xff1a;1、每天坚持早睡早起。晚上23&#xff1a;00前睡&#xff0c;早上6:00前起&#xff0c;坚持用心中的梦想唤醒自己。2、每天坚持阅读。尤其要读名人传记&#xff0c;用名人的经历启迪自己&#xff0c;站在巨人的肩上看世界。3、每天坚持按日程计划行事。…

JDBC操作数据库

JDBC操作数据库 JdbcTemplate是Spring框架提供的一个对JDBC进行封装的工具类&#xff0c;它用于简化JDBC的使用。 以下是使用JdbcTemplate操作数据库的一些常见方法&#xff1a; 1、使用JdbcTemplate插入数据&#xff1a; Autowired private JdbcTemplate jdbcTemplate;pub…

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;从而定位问题所在。以下是一些嵌入式日志调试的基本规则和示例代码。 日志调试的基本规则 确定日志…

C++使用QtHttpServer开发服务端Server的Http POST接口和客户端Client示例

Client HTTP POST 假设http://127.0.0.1:8888/post/是一个能够接受POST请求的路径&#xff0c;我们想要向它提交一段json数据&#xff0c;用Qt可以这样实现&#xff1a; Suppose we want to make an HTTP POST with json body to http://127.0.0.1:8888/post/. QCoreApplica…

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

只要短视频/直播做的好&#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#所有…

SASS语法基础

SASS基础语法 1. 变量和嵌套 变量&#xff1a;在SASS中&#xff0c;您可以使用变量来存储重复使用的值&#xff0c;例如颜色、字体大小等。定义一个变量时&#xff0c;使用$符号&#xff0c;如下所示&#xff1a; // 定义变量 $primary-color: #0074D9;// 使用变量 body {ba…

JavaScript逻辑中断

在JavaScript中&#xff0c;逻辑中断通常指的是在代码执行过程中&#xff0c;由于某些条件或异常&#xff0c;导致代码的正常流程被打断或改变。这种中断可以是由控制流语句&#xff08;如if、for、while、switch等&#xff09;引起的&#xff0c;也可以是由异常处理&#xff0…

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

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

华为FPGA工程师面试题

FPGA工程师面试会涉及多个方面&#xff0c;包括基础知识、项目经验、编程能力、硬件调试和分析等。以下是一些必问的面试题&#xff1a; 基础知识题&#xff1a; 请解释FPGA的基本组成和工作原理。描述FPGA中的可编程互联资源以及它们在构建复杂数字电路中的作用。请解释嵌入式…

基于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…

移植GT9XX遇到的问题

gt9xx驱动移植触摸不准&#xff1a;厂家提供的cfg有问题&#xff0c;重新问厂家要一份正确的 XY坐标镜像&#xff1a; 在gtp_get_points函数里修改代码&#xff1a; if(ts->pdata->reverse_xy) {points[i].x ts->pdata->abs_size_x - (coor_data[1] | (coor_da…

代码实操学会socket网络编程

一、网络编程接口 网络编程接口是一组提供给开发者使用的函数和方法集合,用于在应用程序中实现网络通信功能。它提供了一种抽象层,使得开发者能够使用高级编程语言(如C、C++、Java、Python等)来进行网络编程,而无需直接处理底层的网络协议和细节。 网络编程接口的功能和作…

容器中运行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 …

【小海实习日记】金融-现货以及合约理解

在股票和金融市场中&#xff0c;“单项持仓”和“双向持仓”是两个常见的概念&#xff0c;主要用于描述投资者在市场中的头寸及其策略。 单项持仓&#xff08;单向持仓&#xff09; 单项持仓是指投资者在市场中只持有一种方向的头寸&#xff08;多头或空头&#xff09;&#…