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

为什么直接 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++ 没有 java 的 Class.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,否则崩溃
抽象工厂本身不解决“字符串到类型”的映射,那是简单工厂或注册表的职责;真正关键的是:谁持有创建逻辑、谁承担变化——这决定了你该选哪种工厂结构。