一、前言
在现代C++开发中,工厂模式是常见的设计模式之一,能够有效地解耦对象创建与使用代码。本文介绍一个模板类 ComponentsFactory,它运用了模板编程和工厂模式,实现了一种动态的对象创建方式。通过该工厂,我们可以基于类的描述信息在运行时注册并生成对象,而无需直接依赖具体类。这种设计在需要动态扩展组件或模块的系统中非常实用。
二、什么是模板工厂模式
在C++中,工厂模式(Factory Pattern)通常用于创建复杂的对象实例,将对象的创建与使用解耦。而模板工厂模式在工厂模式的基础上引入了模板编程,以支持类型的多样性。本文中的 ComponentsFactory 便是一个模板工厂类,它能根据注册的类名信息来创建对应类型的对象。
二、 ComponentsFactory 的设计概述
我们定义一个模板类 ComponentsFactory,其中包含了一组静态方法,负责将类型 C 的子类动态注册并创建。下面,我们通过 ComponentsFactory 的代码分步进行功能说明。
template<typename C>
class ComponentsFactory {
这个类模板 ComponentsFactory 接收一个类型参数 C,它是工厂的基类或接口类型。工厂将创建的对象必须继承自 C,使得我们能够通过多态来操作这些对象。
三、实现方法详解
3.1 注册类型:registerClass
registerClass 方法用于将类型 T 注册到工厂中。注册时需要提供一个 ComponentsDesc 类型的对象,该对象包含类的描述信息(如类名等)。
template<typename T>
static void registerClass(const ComponentsDesc& registerComponent) {constructors().insert(registerComponent, &constructorHelper<T>);
}
在这个方法中:
- registerComponent 是 ComponentsDesc 类型的类描述信息,用于识别类。
- constructors() 是一个哈希表,存储了类描述信息和对应的构造函数指针。
- constructorHelper 是一个构造辅助函数,负责创建具体类型 T 的对象实例。
3.2 基于类名动态创建对象:create
create 方法根据提供的类名(registerComponent)来创建对象实例。它首先在 constructors 中查找匹配的构造函数指针,然后调用该指针来创建对象。
static C* create(const QByteArray& registerComponent, bool realTrade, C* parent = nullptr) {Constructor constructor = nullptr;QString tooltip;QList<ComponentsDesc> descs = keys();foreach (ComponentsDesc var, descs) {if(var.className == registerComponent){constructor = constructors().value(var);tooltip = var.componentsName;break;}}if (constructor == nullptr)return nullptr;C* obj = (*constructor)(realTrade, parent);if(obj) {obj->setProperty("className", registerComponent);obj->setProperty("toopTip", tooltip);}return obj;
}
该方法的主要流程:
- 遍历 constructors,查找与 registerComponent 匹配的构造函数。
- 找到构造函数后,调用它创建对象。
- 若未找到对应的构造函数,则返回 nullptr。
- 如果对象创建成功,将 className 和 toopTip 属性设置到对象上。
- 这个方法确保了对象的创建逻辑与使用代码分离,使得系统可以动态加载新类型。
3.3 使用完整的描述信息创建实例:createByWholeInfo
createByWholeInfo 方法与 create 类似,不同的是它使用一个 ComponentsDesc 对象作为参数,从而在创建对象时可以利用完整的类描述信息。
static C* createByWholeInfo(const ComponentsDesc& registerComponent, bool realTrade, C* parent = nullptr) {Constructor constructor = constructors().value(registerComponent);if (constructor == nullptr)return nullptr;C* obj = (*constructor)(realTrade, parent);if (obj) obj->setProperty("className", registerComponent.className);return obj;
}
这为创建提供了更大的灵活性,例如在需要为特定类设置更多属性时非常有用。
3.4 查看已注册的类信息:keys
keys 方法返回所有已注册的 ComponentsDesc 列表,方便查询和调试。
static QList<ComponentsDesc> keys() { return constructors().keys(); }
3.5 私有成员:构造函数指针和辅助函数
私有成员包括:
- 构造函数指针类型 Constructor。
- constructorHelper 函数,它是一个模板函数,用于具体创建对象。
typedef C* (*Constructor)(bool realTrade, C* parent);template<typename T>
static C* constructorHelper(bool realTrade, C* parent) {return new T(realTrade, parent);
}
3.6 存储类和构造函数的映射:constructors
constructors 返回一个静态哈希表,它将类描述信息与构造函数指针关联起来。
static QHash<ComponentsDesc, Constructor>& constructors() {static QHash<ComponentsDesc, Constructor> instance;return instance;
}
四、代码总结
ComponentsFactory 通过模板工厂模式实现了动态创建对象的能力。它的核心功能包括:
- 使用 registerClass 注册不同类型的类,使得工厂可以动态扩展支持的类型。
- 通过 create 和 createByWholeInfo 方法实现动态对象创建,避免硬编码类类型。
- 提供 keys 方法查询注册信息,使得工厂状态透明可查。
- 这种设计为系统的扩展性和维护性提供了极大的便利,是一种优雅的工厂模式实现方式。
五、应用场景
这个模板工厂可以用于:
- 插件系统:根据类描述动态加载和创建插件对象。
- 组件管理:在需要灵活添加、移除或更改组件的系统中。
- 依赖注入:将创建逻辑从业务逻辑中解耦,特别适用于复杂系统的初始化。
- 通过这种工厂模式,不仅提升了代码的灵活性,也大大降低了系统的耦合度。