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


    工厂方法模式的瑕疵

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

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

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

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

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

    注册表

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

    #ifndef Reflection_H
    #define Reflection_H
    #include
    #include
    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);
    #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(class_map[vendor_name])(args...);
    }
    }
    //向map中注册关键字和类的构造函数
    static bool Register(const std::string &vendor_name, void *ctor_ptr)
    {
    CRRC_DEBUG("Register class_name:"<
    GetStaticFuncMap()[vendor_name] = ctor_ptr;
    return true;
    }
    private:
    //获取全局唯一的map
    //map记录了关键字和类的构造函数的映射关系
    static std::mapvoid*>& GetStaticFuncMap()
    {
    static std::mapvoid*> class_map_;
    return class_map_;
    }
    };
    #endif //Reflection_H

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

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

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

    //运行时确定数组大小,且确定后不可改变
    auto camera_devices_ = std::make_unique[]>(onlined_camera_num_);
    for(int i = 0; i < onlined_camera_num_; ++i)
    {
    auto p_factory = Object::CreateObject(camera_name[i]);//camera_name[i]中元素是提前获取的与连接的相机对应的供应商名称
    if (!p_factory)
    continue;
    else
    camera_devices_[i] = p_factory->CreateCameraDevice();
    delete p_factory;
    }
  • 相关阅读:
    【练习八 结构体(强化)编程题7. 公共钥匙盒】
    ssm医院挂号系统的设计与实现毕业设计源码211633
    Talk|北京大学PKU-DAIR余昭辰:从多模态理解到生成 - 从LLM到Diffusion Model
    摄像头参数介绍 ———— 白平衡
    InfluxDB时序数据库
    使用Pega进行一个简单的RPA程序开发
    17 软专
    使用百度EasyDL实现明厨亮灶厨师帽识别
    2024年新版宝塔面板如何安装WordPress网站教程
    设计模式之原型模式
  • 原文地址:https://www.cnblogs.com/paw5zx/p/18229334