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


    工厂方法模式的瑕疵

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

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

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

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

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

    注册表

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

    1. #ifndef Reflection_H
    2. #define Reflection_H
    3. #include <map>
    4. #include <string>
    5. template <typename T, typename... ArgType>
    6. void* CreateInstance(ArgType... args)
    7. {
    8. return new T(args...);
    9. }
    10. //需要反射的类使用该宏注册
    11. #ifndef ReflectRegister
    12. #define ReflectRegister(identifier, class_name, ...) \
    13. static bool __type##class_name = Object::Register(identifier, (void*)CreateInstance<class_name, ##__VA_ARGS__>);
    14. #endif
    15. class Object
    16. {
    17. public:
    18. template <typename BaseClass, typename... ArgType>
    19. static BaseClass *CreateObject(const std::string &vendor_name, ArgType... args)
    20. {
    21. using CreateFactory = BaseClass *(*)(ArgType...);
    22. auto& class_map = GetStaticFuncMap();
    23. auto iter = class_map.find(vendor_name);
    24. if (iter == class_map.end())
    25. {
    26. CRRC_ERROR("class_name not found in map");
    27. return nullptr;
    28. }
    29. else
    30. {
    31. CRRC_DEBUG("class_name found in map");
    32. return reinterpret_cast<CreateFactory>(class_map[vendor_name])(args...);
    33. }
    34. }
    35. //向map中注册关键字和类的构造函数
    36. static bool Register(const std::string &vendor_name, void *ctor_ptr)
    37. {
    38. CRRC_DEBUG("Register class_name:"<<vendor_name);
    39. GetStaticFuncMap()[vendor_name] = ctor_ptr;
    40. return true;
    41. }
    42. private:
    43. //获取全局唯一的map
    44. //map记录了关键字和类的构造函数的映射关系
    45. static std::map<std::string, void*>& GetStaticFuncMap()
    46. {
    47. static std::map<std::string, void*> class_map_;
    48. return class_map_;
    49. }
    50. };
    51. #endif //Reflection_H

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

    1. class BaslerCameraDeviceFactory : public CameraDeviceFactory
    2. {
    3. public:
    4. std::shared_ptr<CameraDevice> CreateCameraDevice() override
    5. {
    6. return std::make_shared<BaslerCameraDevice>();
    7. }
    8. };
    9. ReflectRegister("Basler", BaslerCameraDeviceFactory);

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

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

    文章转载自:paw5zx

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

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

  • 相关阅读:
    【物联网安全知多少?】
    2022-06-28 工作记录--React-react-intersection-observer实现图片在可视范围内时加上其对应动图
    极端气候肆虐催化,碳中和带出了一个“再生时代”
    最全的 ES 重点内容整理(上)
    Bridge 2024 新版本 Bridge 2024 mac软件特色和功能
    docker 入门篇 (镜像制作+数据卷)
    猫罐头哪个牌子好?盘点十大猫罐头品牌排行榜!
    企业园区办公室无线覆盖部署案例
    化繁为简,聊一聊复制状态机系统架构抽象
    MyBatis 关联映射
  • 原文地址:https://blog.csdn.net/kfashfasf/article/details/139437619