设计模式学习(二)工厂模式——工厂方法模式+注册表
工厂方法模式的瑕疵
在前一篇笔记 中我们介绍了工厂方法模式,示例的类图如下:
前文中提到
工厂方法模式把提供方原来的简单工厂类的内部判断逻辑转移到了客户端代码,这让客户端代码违反了开闭原则
下面举例说明。
示例
考虑一种情况:现在要在程序运行时,根据外部资源,动态的实例化对象。也就是说在编译期我们无法知道要实例化的对象的类型。因此在实例化的过程中,就需要加以判断。
例如,在我的例子中,要根据连接到主机的相机来实例化相机对象,那么客户端(使用工厂方法创建实例的一方)使用工厂方法模式创建对象的时候,代码可能是这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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]) 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去适配,这违反了开闭原则,将使客户端代码变得冗长且难以维护。
注册表
为了解决上面问题,我们可以实现一个类型的注册表,允许动态创建对象。这种方法通过将关键字映射到构造函数指针,使得可以根据字符串名称动态地实例化对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #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()) { return nullptr; } else { return reinterpret_cast<CreateFactory>(class_map[vendor_name])(args...); } }
static bool Register(const std::string &vendor_name, void *ctor_ptr) { GetStaticFuncMap()[vendor_name] = ctor_ptr; return true; }
private: static std::map<std::string, void*>& GetStaticFuncMap() { static std::map<std::string, void*> class_map_; return class_map_; } };
#endif
|
在具体相机工厂中,我们可以使用ReflectRegister
注册此类(以Basler相机为例,其余类似):
1 2 3 4 5 6 7 8 9 10
| class BaslerCameraDeviceFactory : public CameraDeviceFactory { public: std::shared_ptr<CameraDevice> CreateCameraDevice() override { return std::make_shared<BaslerCameraDevice>(); } };
ReflectRegister("Basler", BaslerCameraDeviceFactory);
|
好了,现在回头再看客户端使用工厂方法模式创建对象的代码,就可以简化为:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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]); if (!p_factory) continue; else camera_devices_[i] = p_factory->CreateCameraDevice(); delete p_factory; }
|