c++怎么实现工厂设计模式_c++ 抽象工厂与对象动态创建【案例】

16次阅读

直接new无法满足多态创建需求,因其将具体子类类型硬编码在调用点,违反开闭原则;工厂模式通过封装new逻辑、依赖抽象类型,实现运行时动态创建。

c++怎么实现工厂设计模式_c++ 抽象工厂与对象动态创建【案例】

为什么直接 new 不能满足多态创建需求

当业务需要根据配置、用户输入或运行时条件决定创建哪种子类对象时,硬编码 new DerivedA()new DerivedB() 会把具体类型写死在调用点,破坏开闭原则。后续每新增一个子类,都得改所有创建逻辑——这是工厂模式要解决的核心问题。

  • 抽象基类(如 Shape)定义接口,不负责实例化
  • 工厂类(如 ShapeFactory)封装 new,只暴露统一创建接口
  • 调用方只依赖工厂和抽象类型,完全不知道具体子类名

简单工厂:用字符串/枚举控制 new 哪个子类

适合子类数量固定、创建逻辑不复杂的情况。它不是 goF 23 种之一,但最常用、最易理解。

class Shape { public:     virtual void draw() = 0;     virtual ~Shape() = default; };  class Circle : public Shape { public:     void draw() override { std::cout << "Drawing Circlen"; } };  class Rectangle : public Shape { public:     void draw() override { std::cout << "Drawing Rectanglen"; } };  class ShapeFactory { public:     Static std::unique_ptr create(const std::string& type) {         if (type == "circle") return std::make_unique();         if (type == "rectangle") return std::make_unique();         throw std::runtime_error("Unknown shape type: " + type);     } };
  • 返回 std::unique_ptr 而非裸指针,避免内存泄漏
  • 工厂方法是 static,调用无需实例化工厂对象
  • 错误类型名会直接抛出异常,调用方必须处理,不能静默失败

抽象工厂:创建一族相关对象,比如不同主题的 ui 控件

当系统需要创建多个有内在关联的对象(如 Button + checkbox),且这些对象需保持风格一致(windows 风 vs macos 风),抽象工厂就派上用场。

class Button { public: virtual void render() = 0; }; class Checkbox { public: virtual void render() = 0; };  class WindowsButton : public Button { void render() override { std::cout << "Win buttonn"; } }; class MacOSButton : public Button { void render() override { std::cout << "Mac buttonn"; } };  class WindowsCheckbox : public Checkbox { void render() override { std::cout << "Win checkboxn"; } }; class MacOSCheckbox : public Checkbox { void render() override { std::cout << "Mac checkboxn"; } };  class GUIFactory { public:     virtual std::unique_ptr
  • 每个具体工厂(WindowsFactory)保证返回的对象属于同一“族”,避免混搭
  • 客户端代码只依赖 GUIFactory 接口,通过传入不同工厂实例切换整套 UI 风格
  • 新增主题只需加一对具体类 + 一个工厂子类,不修改已有代码

动态创建:从字符串名自动 new 对象(需注册机制)

c++ 没有 javaClass.forName(),要实现“根据类名字符串创建对象”,必须手动注册构造函数指针。

立即学习C++免费学习笔记(深入)”;

using CreatorFunc = std::unique_ptr(*)(); std::map g_creatorMap;  template void registerCreator(const std::string& name) {     g_creatorMap[name] = []() -> std::unique_ptr {         return std::make_unique();     }; }  // 初始化时注册 void initFactories() {     registerCreator("circle");     registerCreator("rectangle"); }  std::unique_ptr createShape(const std::string& name) {     auto it = g_creatorMap.find(name);     if (it != g_creatorMap.end()) return it->second();     throw std::runtime_error("No creator registered for: " + name); }
  • 注册必须在 main() 开始前完成(可用静态变量触发)
  • 模板函数 registerCreator 避免重复写 Lambda,提升可读性
  • 若类名来自配置文件或网络,务必校验 name 是否存在于 g_creatorMap,否则崩溃

抽象工厂本身不解决“字符串到类型”的映射,那是简单工厂或注册表的职责;真正关键的是:谁持有创建逻辑、谁承担变化——这决定了你该选哪种工厂结构。

text=ZqhQzanResources