工厂类只负责创建对象,不处理业务逻辑:仅分配内存、调用构造函数、返回智能指针;禁止日志、连接数据库等初始化操作,不持有状态,不管理生命周期,确保与使用方彻底解耦。

工厂类怎么只管创建,不碰业务逻辑
工厂模式的核心就是让对象创建和后续使用彻底解耦。关键不是“写个工厂类”,而是确保工厂里 create() 方法只做三件事:分配内存、调用构造函数、返回指针(或引用),其余一概不管——比如不存实例、不调用 run()、不传业务参数进构造函数(除非是对象自身必需的配置)。
常见错误是把工厂写成“初始化中心”:在 create() 里硬编码日志、连接数据库、读配置文件……这会让工厂变重、难测、无法复用。
- 工厂返回类型建议统一用智能指针:
std::unique_ptr<base>,避免裸指针管理风险 - 构造所需参数应通过工厂方法参数传入,而非从全局变量或单例里取
- 如果不同子类需要不同参数集,用结构体封装或重载多个
create(),别用万能std::map<:string std::any></:string>
使用者如何完全不知道具体类型
调用方只依赖抽象基类接口,连头文件都不该 include 具体实现类。例如使用者代码里只能出现 std::unique_ptr<shape></shape> 和 shape->draw(),绝不能有 #include "Circle.h" 或 new Circle(...)。
容易踩的坑是“伪抽象”:基类没定义纯虚函数,或派生类暴露了额外 public 成员,导致使用者无意中强转或访问具体类型。
- 基类必须有虚析构函数:
virtual ~Shape() = default;,否则delete智能指针时行为未定义 - 所有可扩展行为必须声明为
virtual(最好= 0),禁止在基类里加具体实现逻辑 - 工厂头文件只
#include基类头,实现文件才#include各个派生类头——这是隔离的关键物理边界
怎么避免工厂自己变成全局状态
工厂本身不该持有已创建对象的列表、缓存、计数器之类的状态。一旦工厂开始“记账”,它就从“创建工具”退化成了“对象管理器”,违背了单一职责。
典型反模式:写个 SingletonFactory,里面用 std::vector<:unique_ptr>></:unique_ptr> 存所有实例,再提供 getAll() 接口——这等于把内存管理和生命周期控制权又拿回工厂手里。
- 工厂类设计为无状态:所有成员变量删光,只留静态
create()方法(或静态成员函数对象) - 如需缓存,交给上层使用者(比如服务类持有一个
std::unordered_map缓存工厂产出的对象) - 若必须控制对象数量(如连接池),那是对象池模式,不是工厂模式;该另起一个
ConnectionPool类,它内部才用工厂来创建连接
动态加载类时工厂怎么保持干净
当用 dlopen() / LoadLibrary() 加载插件时,工厂容易变成“符号解析器”:手动 dlsym() 找构造函数地址、强制类型转换、管理句柄……这些细节必须封装到工厂内部,对外仍保持 create("json_parser") 这样的简洁接口。
难点在于跨模块的 ABI 稳定性。C++ 没有标准二进制接口,所以不要在插件里导出 C++ 类,而要导出 C 风格函数指针。
- 插件导出两个 C 函数:
create_instance()返回void*,destroy_instance(void*) - 工厂内部用
reinterpret_cast<base>(ptr)转换,但前提是 Base 的内存布局简单(无虚继承、无多继承) - 更安全的做法:插件只导出工厂函数,由主程序统一链接基类虚表——即插件不直接 new 对象,而是调用主程序提供的工厂注册回调
真正难的不是写工厂,是守住“创建”这个动作的纯粹性。只要工厂开始处理资源释放、生命周期策略、运行时配置合并,它就已经不是工厂了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











