首页 > 其他分享 >设计模式学习(二)工厂模式——工厂方法模式+注册表

设计模式学习(二)工厂模式——工厂方法模式+注册表

时间:2024-06-03 17:46:03浏览次数:22  
标签:std map name factory 工厂 camera 注册表 设计模式 class

目录

工厂方法模式的瑕疵

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

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

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

//运行时确定数组大小,且确定后不可改变
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__>);
#endif

class 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;
    else
        camera_devices_[i] = p_factory->CreateCameraDevice();
        
    delete p_factory;
}

标签:std,map,name,factory,工厂,camera,注册表,设计模式,class
From: https://www.cnblogs.com/paw5zx/p/18229334

相关文章

  • c/c++设计模式---享元模式
    引入享元模式:围棋游戏:namespace_nmsp1{enumEnumColor//棋子类型{Black,//黑White//白};structPosition//棋子位置{intm_x;intm_y;Position(inttmpx,inttmpy):m_x(tmpx),m_y(tmpy){}......
  • 常用设计模式总结,附完整图解
    UML类图类图定义规则属性和方法前加上(+、-、#、留空)分别代表:公开(public)、私有(private)、保护(protected)、缺省(default)方法括号内为参数类型,冒号后为返回值类型下划线表示静态(static),斜体表示抽象(abstract) 类图关系表示法其中关联、聚合、组合,比较容易混淆,它们的区别:关......
  • 英伟达赢麻了!马斯克xAI超级算力工厂曝光,10万块H100、数十亿美元
        ChatGPT狂飙160天,世界已经不是之前的样子。新建了免费的人工智能中文站https://ai.weoknow.com新建了收费的人工智能中文站https://ai.hzytsoft.cn/更多资源欢迎关注英伟达:尽管建,用的还是我的芯片,最近几年,随着大语言模型的飞速发展与迭代,科技巨头们都竞相投入......
  • Java高并发核心编程.卷2,多线程、锁、JMM、JUC、高并发设计模式 (尼恩)电子版百度云
    书获取链接:python33  。c o  m我的阅读笔记:多线程:介绍Java多线程的基础概念,如线程的创建、启动、状态转换、线程间通信等。锁:深入探讨Java中的各种锁机制,包括内置锁(synchronized)、ReentrantLock、ReadWriteLock等,以及它们的使用场景和性能特点。Java内存模型(JMM):解释J......
  • 设计模式之原型模式
    问题背景在开发一个图形设计软件时,我们面临一个常见的需求:用户需要频繁地创建和编辑各种图形,如圆形、矩形和多边形。其中,许多图形元素在属性上非常相似,比如颜色、大小或样式可能只有细微的差别。用户希望能够快速复制一个已有图形,然后对其进行小的修改,而不是每次都从零开始......
  • 网关(Gateway)- 自定义过滤器工厂
    自定义过滤工厂类DemoGatewayFilterFactorypackagecom.learning.springcloud.custom;importorg.apache.commons.lang.StringUtils;importorg.springframework.cloud.gateway.filter.GatewayFilter;importorg.springframework.cloud.gateway.filter.GatewayFilterChai......
  • 网关(Gateway)- 内置过滤器工厂
    官方文档:SpringCloudGateway内置过滤器工厂AddRequestHeaderGatewayFilterFactory为请求添加HeaderHeader的名称及值配置说明server:port:8088spring:application:name:api-gatewaycloud:nacos:discovery:server-addr:127.......
  • 抽象工厂模式
    抽象工厂模式解决的是一系列相互依赖的对象的创建。classMyConnect{};classMyDatabse{};classMyCommand{};//sqlServer的连接classSqlServerConnect:publicMyConnect{};classSqlServerDatabse:publicMyDatabse{};classSqlServerCommand:publicMyComm......
  • 观察者设计模式
    实现C++中的观察者设计模式通常包括以下几个关键组件: 1.**Subject(主题)**:这是被观察的对象,它维护一个观察者列表,并提供注册、注销观察者的方法以及通知所有观察者的方法。 2.**Observer(观察者)**:这是一个抽象接口或基类,定义了观察者需要实现的更新接口(如`update()`方法),以......
  • (工厂+策略)实现登录功能
    原始代码业务层UserService@ServicepublicclassUserService{publicLoginResplogin(LoginReqloginReq){if(loginReq.getType().equals("account")){System.out.println("用户名密码登录");//执行用户密码登录逻辑......