工厂类封装new以解耦构造逻辑与实例化决策,推荐返回std::unique_ptr、结构体传参、字符串映射创建器、小写下划线类型名、配置前置校验、异常冒泡及资源自动清理。

用工厂类封装 new,避免裸 new 泛滥
裸调用 new 创建一堆对象,配置一变就得改代码,维护成本高。工厂类的核心作用不是炫技,是把“怎么造”和“造什么”拆开——构造逻辑收在工厂里,实例化决策交给配置。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 工厂方法返回
std::unique_ptr<base>,别用裸指针或std::shared_ptr(除非真需要共享所有权) - 构造函数参数尽量走结构体传入(如
Config{.type="tcp", .port=8080}),别堆一堆int、std::string参数,加字段不破接口 - 工厂内部用
if-else或std::map映射类型字符串到构造器 lambda,别用宏或模板特化去“泛型化”工厂——配置驱动的前提是运行时可变,编译期展开反而锁死扩展性
配置文件里写类型名,别写类名全路径
YAML/JSON 里直接写 "TcpClient" 比写 "com::myapp::network::TcpClient" 更实际。前者可读、可编辑、可热重载;后者一改命名空间,配置全废,还容易拼错。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 在工厂注册阶段用字符串字面量绑定类型,例如:
factory.register_creator("http", []{ return std::make_unique<httpclient>(); });</httpclient> - 配置解析后校验
type字段是否存在对应 creator,缺失时立刻抛std::runtime_error("unknown type: " + type),别静默 fallback - 类型名统一小写+下划线(如
"redis_pool"),避免大小写混用导致 Linux 下加载失败
批量创建时注意构造异常传播和资源清理
循环里调 factory.create(config),中间某个对象构造失败(比如网络初始化超时),前面已创建的对象得自动释放——否则内存泄漏、句柄堆积、状态不一致。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 用
std::vector<:unique_ptr>></:unique_ptr>接收结果,构造失败时 vector 自动析构已存对象 - 别在工厂里捕获构造异常再吞掉;让异常冒泡,由上层决定是重试、跳过还是终止整批创建
- 如果构造函数可能持有外部资源(如打开文件、绑定 socket),确保其析构函数是
noexcept,否则 vector 在异常途中析构可能调用std::terminate
不要在工厂里做配置校验和默认值填充
工厂只负责“按需造一个”,不负责“教用户怎么填配置”。校验和补缺应该前置——在配置加载后、传给工厂前就做完。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 写独立的
validate_and_fill_defaults(Config& c)函数,检查必要字段是否存在,补充timeout=3000这类默认值 - 工厂函数签名保持干净:只接受已验证的
const Config&,不处理空字符串、负端口号等非法输入 - 这样分层后,单元测试能分别覆盖校验逻辑和工厂逻辑,而不是在工厂测试里塞一堆错误配置 case
配置驱动的批量创建,真正难的不是写工厂,是定义清楚配置 schema 和校验边界。很多人卡在“工厂返回空指针要不要报错”这种问题上,其实是没想明白:配置解析失败是配置层的事,构造失败是业务层的事,工厂只是中间那根不能弯的钢管。











