C++ 工厂模式(转载)

张开发
2026/4/19 10:45:10 15 分钟阅读

分享文章

C++ 工厂模式(转载)
转载自https://blog.csdn.net/XiaoBinbest/article/details/155454497 作者学不完了怎么办前言工厂模式是创建型设计模式的核心成员其核心目标是封装对象的创建过程将对象创建与使用逻辑解耦通过统一的“工厂”接口创建不同类型的对象无需暴露对象的具体创建细节。在 C 开发中工厂模式广泛应用于对象创建逻辑复杂、产品类型多变、需要统一管理对象生命周期的场景如框架组件、插件系统、数据库连接池、UI 组件库等。根据封装程度和适用场景工厂模式分为三类简单工厂模式、工厂方法模式、抽象工厂模式三者是“从简单到复杂、从单一到多样”的递进关系。一、工厂模式的核心目标与设计思想1.1 核心目标封装创建逻辑将对象的创建细节如构造参数、初始化步骤、依赖注入隐藏在工厂类中使用者无需关心“如何创建”只需调用工厂接口即可。解耦创建与使用使用者仅依赖产品的抽象接口而非具体实现修改产品实现或新增产品时无需修改使用代码符合“开闭原则”。统一管理对象通过工厂集中控制对象的创建、初始化、销毁便于添加日志、缓存、权限校验等统一逻辑。支持灵活扩展新增产品时只需扩展工厂或新增具体工厂无需修改现有代码。1.2 核心设计思想依赖倒置原则依赖抽象产品接口、工厂接口不依赖具体实现具体产品、具体工厂。里氏替换原则具体产品可替换抽象产品具体工厂可替换抽象工厂不影响使用逻辑。单一职责原则工厂类仅负责对象创建产品类仅负责业务逻辑各司其职。二、工厂模式的三种核心类型含 C 实现2.1 简单工厂模式Simple Factory Pattern2.1.1 定义由一个单一工厂类负责所有产品的创建通过传入参数如类型标识工厂类动态决定创建哪种具体产品。本质是“集中式创建”将所有产品的创建逻辑封装在一个工厂中。2.1.2 结构组成抽象产品Product所有具体产品的基类通常是抽象类/接口含纯虚函数定义核心业务方法。具体产品ConcreteProduct抽象产品的实现类包含具体业务逻辑。工厂类Factory核心类提供静态或成员方法根据参数创建并返回具体产品的指针/引用。2.1.3 代码实现#include iostream #include string #include memory // 智能指针避免内存泄漏 // 1. 抽象产品定义产品的核心接口 class Shape { public: virtual ~Shape() default; // 虚析构确保子类析构被调用 virtual void draw() const 0; // 纯虚函数子类必须实现 }; // 2. 具体产品圆形实现抽象产品接口 class Circle : public Shape { public: void draw() const override { std::cout 绘制圆形Circle std::endl; } }; // 具体产品矩形实现抽象产品接口 class Rectangle : public Shape { public: void draw() const override { std::cout 绘制矩形Rectangle std::endl; } }; // 具体产品三角形实现抽象产品接口 class Triangle : public Shape { public: void draw() const override { std::cout 绘制三角形Triangle std::endl; } }; // 3. 工厂类负责所有形状产品的创建 class ShapeFactory { public: // 静态工厂方法根据类型参数创建具体产品返回智能指针自动管理内存 static std::unique_ptrShape createShape(const std::string type) { if (type circle) { return std::make_uniqueCircle(); } else if (type rectangle) { return std::make_uniqueRectangle(); } else if (type triangle) { return std::make_uniqueTriangle(); } else { throw std::invalid_argument(不支持的形状类型 type); } } }; // 测试代码使用者仅依赖抽象产品和工厂不关心具体实现 int main() { try { // 工厂创建圆形 auto circle ShapeFactory::createShape(circle); circle-draw(); // 工厂创建矩形 auto rectangle ShapeFactory::createShape(rectangle); rectangle-draw(); // 工厂创建三角形 auto triangle ShapeFactory::createShape(triangle); triangle-draw(); // 错误类型抛出异常 auto invalid ShapeFactory::createShape(square); } catch (const std::exception e) { std::cerr 错误 e.what() std::endl; } return 0; }输出结果绘制圆形Circle 绘制矩形Rectangle 绘制三角形Triangle 错误不支持的形状类型square2.1.4 优缺点与使用场景核心优点实现简单仅需一个工厂类代码量少易于理解和维护。封装性好使用者无需知道产品的创建细节只需传入类型参数。统一管理产品创建逻辑集中在工厂便于添加日志、缓存等扩展逻辑。核心缺点违反开闭原则新增产品时必须修改工厂类的createShape方法添加新的if-else导致工厂类逐渐臃肿。工厂类职责过重所有产品的创建逻辑都在一个工厂中一旦工厂出错所有产品创建都会受影响。扩展性差产品类型过多时if-else分支会变得冗长维护困难。适用场景产品类型较少如 3-5 种且不常新增产品。简单场景无需复杂的扩展机制如小型工具类、简单组件创建。2.2 工厂方法模式Factory Method Pattern2.2.1 定义为解决简单工厂的“开闭原则”问题将单一工厂拆分为多个具体工厂每个具体产品对应一个具体工厂抽象出统一的工厂接口新增产品时只需新增“具体产品 具体工厂”无需修改现有代码。本质是“分拆式创建”将创建职责分散到各个具体工厂。2.2.2 结构组成抽象产品Product所有具体产品的基类抽象类/接口。具体产品ConcreteProduct抽象产品的实现类。抽象工厂AbstractFactory所有具体工厂的基类抽象类/接口含纯虚函数createProduct()定义产品创建接口。具体工厂ConcreteFactory抽象工厂的实现类每个具体工厂仅负责创建一种具体产品。2.2.3 C 实现代码#include iostream #include memory // 1. 抽象产品形状接口 class Shape { public: virtual ~Shape() default; virtual void draw() const 0; }; // 2. 具体产品圆形 class Circle : public Shape { public: void draw() const override { std::cout 绘制圆形Circle std::endl; } }; // 具体产品矩形 class Rectangle : public Shape { public: void draw() const override { std::cout 绘制矩形Rectangle std::endl; } }; // 3. 抽象工厂定义工厂的核心接口创建产品 class ShapeFactory { public: virtual ~ShapeFactory() default; virtual std::unique_ptrShape createShape() const 0; // 纯虚函数子类实现 }; // 4. 具体工厂圆形工厂仅创建圆形 class CircleFactory : public ShapeFactory { public: std::unique_ptrShape createShape() const override { return std::make_uniqueCircle(); } }; // 具体工厂矩形工厂仅创建矩形 class RectangleFactory : public ShapeFactory { public: std::unique_ptrShape createShape() const override { return std::make_uniqueRectangle(); } }; // 测试代码使用者依赖抽象工厂和抽象产品可灵活替换具体工厂 int main() { // 圆形工厂创建圆形 std::unique_ptrShapeFactory circleFactory std::make_uniqueCircleFactory(); auto circle circleFactory-createShape(); circle-draw(); // 矩形工厂创建矩形 std::unique_ptrShapeFactory rectFactory std::make_uniqueRectangleFactory(); auto rectangle rectFactory-createShape(); rectangle-draw(); // 新增产品如三角形仅需添加 Triangle 类和 TriangleFactory 类无需修改现有代码 return 0; }输出结果绘制圆形Circle 绘制矩形Rectangle2.2.4 优缺点与使用场景核心优点符合开闭原则新增产品时只需新增“具体产品 具体工厂”无需修改现有工厂和使用代码。职责单一每个具体工厂仅负责创建一种产品工厂类职责清晰维护简单。扩展性强支持灵活替换具体工厂如替换不同的产品实现符合里氏替换原则。核心缺点类数量膨胀每新增一个产品需同时新增一个具体工厂类导致系统中类的数量增多复杂度上升。逻辑分散创建逻辑分散在多个具体工厂中如需统一修改创建逻辑如添加日志需修改所有具体工厂。使用成本高使用者需知道具体工厂和具体产品的对应关系如创建圆形需用CircleFactory不像简单工厂那样只需传入参数。适用场景产品类型较多且频繁新增产品如插件系统、组件库。需灵活替换产品实现如不同数据库的连接工厂MySQLFactory、OracleFactory。要求严格遵守开闭原则的场景如框架开发。2.3 抽象工厂模式Abstract Factory Pattern2.3.1 定义当系统中存在多个相关联的产品族而非单一产品时抽象工厂模式定义一个“产品族工厂接口”每个具体工厂负责创建一个完整的产品族多个相关产品。本质是“产品族级别的创建”解决“一系列相关产品的统一创建”问题。2.3.2 关键概念产品族一组相关联的产品如“华为产品族”包含华为手机、华为耳机“苹果产品族”包含苹果手机、苹果耳机。产品等级结构同一类型的产品如手机是一个产品等级耳机是另一个产品等级。2.3.3 结构组成抽象产品族多个抽象产品每个产品等级对应一个抽象产品。具体产品族多个具体产品每个具体产品属于一个产品等级且归属于某个产品族。抽象工厂定义创建所有产品等级的接口每个产品等级对应一个创建方法。具体工厂实现抽象工厂接口创建对应产品族的所有产品如华为工厂创建华为手机、华为耳机。2.3.4 C 实现代码#include iostream #include memory #include string // 1. 抽象产品族两个产品等级手机、耳机 // 抽象产品1手机 class Phone { public: virtual ~Phone() default; virtual std::string getName() const 0; }; // 抽象产品2耳机 class Headphone { public: virtual ~Headphone() default; virtual std::string getName() const 0; }; // 2. 具体产品族1华为产品族 // 具体产品1-1华为手机 class HuaweiPhone : public Phone { public: std::string getName() const override { return 华为 Mate 60 Pro; } }; // 具体产品2-1华为耳机 class HuaweiHeadphone : public Headphone { public: std::string getName() const override { return 华为 FreeBuds Pro 3; } }; // 具体产品族2苹果产品族 // 具体产品1-2苹果手机 class IPhone : public Phone { public: std::string getName() const override { return iPhone 16 Pro; } }; // 具体产品2-2苹果耳机 class AirPods : public Headphone { public: std::string getName() const override { return AirPods Pro 2; } }; // 3. 抽象工厂定义创建所有产品等级的接口手机 耳机 class ElectronicFactory { public: virtual ~ElectronicFactory() default; virtual std::unique_ptrPhone createPhone() const 0; virtual std::unique_ptrHeadphone createHeadphone() const 0; }; // 4. 具体工厂1华为工厂创建华为产品族的所有产品 class HuaweiFactory : public ElectronicFactory { public: std::unique_ptrPhone createPhone() const override { return std::make_uniqueHuaweiPhone(); } std::unique_ptrHeadphone createHeadphone() const override { return std::make_uniqueHuaweiHeadphone(); } }; // 具体工厂2苹果工厂创建苹果产品族的所有产品 class AppleFactory : public ElectronicFactory { public: std::unique_ptrPhone createPhone() const override { return std::make_uniqueIPhone(); } std::unique_ptrHeadphone createHeadphone() const override { return std::make_uniqueAirPods(); } }; // 测试代码使用者通过具体工厂获取完整的产品族 int main() { // 华为工厂创建华为手机 华为耳机 std::unique_ptrElectronicFactory huaweiFactory std::make_uniqueHuaweiFactory(); auto huaweiPhone huaweiFactory-createPhone(); auto huaweiHeadphone huaweiFactory-createHeadphone(); std::cout 华为产品族 huaweiPhone-getName() huaweiHeadphone-getName() std::endl; // 苹果工厂创建苹果手机 苹果耳机 std::unique_ptrElectronicFactory appleFactory std::make_uniqueAppleFactory(); auto iphone appleFactory-createPhone(); auto airpods appleFactory-createHeadphone(); std::cout 苹果产品族 iphone-getName() airpods-getName() std::endl; return 0; }输出结果华为产品族华为 Mate 60 Pro 华为 FreeBuds Pro 3 苹果产品族iPhone 16 Pro AirPods Pro 22.3.5 优缺点与使用场景核心优点统一产品族创建一个具体工厂对应一个完整的产品族确保产品族内的产品兼容性如华为手机和华为耳机可联动。符合开闭原则新增产品族时只需新增“具体产品族 具体工厂”无需修改现有代码。封装性更强使用者无需知道产品族内各产品的创建细节只需通过工厂获取整套产品。核心缺点扩展产品等级困难若需新增产品等级如在“手机耳机”基础上新增“平板”需修改抽象工厂接口和所有具体工厂违反开闭原则。复杂度高系统中存在多个抽象产品和具体产品类结构复杂理解和维护成本高。初始化成本高具体工厂需创建产品族的所有产品若产品族较大初始化开销较高。适用场景系统中存在多个相关联的产品族如电子设备、UI 组件主题、数据库驱动连接池。需确保产品族内产品兼容性的场景如同一主题的按钮、输入框、下拉框。不常新增产品等级但可能新增产品族的场景如框架的多主题支持。三、三种工厂模式的对比与选择特性简单工厂模式工厂方法模式抽象工厂模式核心定位单一工厂创建所有产品一个产品对应一个工厂一个产品族对应一个工厂开闭原则兼容性违反新增产品需改工厂符合新增产品加工厂符合产品族违反产品等级类数量少1 工厂 N 产品中N 工厂 N 产品多N 工厂 M*N 产品适用场景产品少、不常扩展产品多、常扩展存在产品族、需保证兼容性使用者复杂度低仅传参数中需知道工厂-产品对应关系高需理解产品族概念扩展成本低修改工厂中新增工厂产品产品族扩展低产品等级扩展高选择建议优先选简单工厂若产品类型少≤5 种、不常新增简单工厂的简洁性是最优选择。选工厂方法若产品类型多、需频繁新增且无产品族关联工厂方法的扩展性更优。选抽象工厂若存在多个相关联的产品族如主题、设备套装需保证产品兼容性抽象工厂是唯一选择。四、C 工厂模式的关键实现技巧4.1 内存管理使用智能指针避免泄漏工厂模式中产品通常通过new创建手动管理内存易导致泄漏。C11 后推荐使用智能指针std::unique_ptr/std::shared_ptrstd::unique_ptr独占所有权适合产品生命周期由使用者管理的场景如示例代码。std::shared_ptr共享所有权适合产品需被多个模块共享的场景如缓存中的产品实例。4.2 工厂的单例化工厂类本身通常无需多个实例创建产品的逻辑是固定的可将工厂设计为单例如 Meyers 单例减少实例创建开销// 单例工厂以简单工厂为例 class ShapeFactory { public: static ShapeFactory getInstance() { static ShapeFactory instance; return instance; } std::unique_ptrShape createShape(const std::string type) { // 创建逻辑... } // 禁止拷贝赋值 ShapeFactory(const ShapeFactory) delete; ShapeFactory operator(const ShapeFactory) delete; private: ShapeFactory() default; // 私有构造 }; // 使用通过单例工厂创建产品 auto circle ShapeFactory::getInstance().createShape(circle);4.3 产品初始化参数传递若产品需要构造参数如配置信息可在工厂方法中添加参数// 抽象产品带参数初始化的数据库连接 class DBConnection { public: virtual ~DBConnection() default; virtual void connect() const 0; }; // 具体产品MySQL 连接 class MySQLConnection : public DBConnection { public: MySQLConnection(const std::string host, int port, const std::string dbName) : host_(host), port_(port), dbName_(dbName) {} void connect() const override { std::cout 连接 MySQL host_ : port_ / dbName_ std::endl; } private: std::string host_; int port_; std::string dbName_; }; // 工厂方法传递初始化参数 class MySQLFactory : public DBFactory { public: std::unique_ptrDBConnection createConnection( const std::string host, int port, const std::string dbName) const { return std::make_uniqueMySQLConnection(host, port, dbName); } }; // 使用 auto mysqlConn MySQLFactory().createConnection(127.0.0.1, 3306, test_db); mysqlConn-connect();4.4 工厂的延迟初始化与缓存对于创建成本高的产品如数据库连接、重型组件可在工厂中添加缓存机制复用已创建的实例class ShapeFactory { public: std::shared_ptrShape getCachedShape(const std::string type) { // 检查缓存 auto it cache_.find(type); if (it ! cache_.end()) { return it-second; } // 缓存未命中创建产品并加入缓存 auto shape createShape(type); cache_.emplace(type, shape); return shape; } private: std::unordered_mapstd::string, std::shared_ptrShape cache_; // 产品缓存 // createShape 方法... };五、工厂模式的适用场景与反场景5.1 适用场景对象创建逻辑复杂产品创建需多步初始化、依赖外部资源如配置文件、网络连接或需校验参数。产品类型多变需频繁新增产品如插件系统、组件库或替换产品实现如不同数据库驱动。需要统一管理对象需集中控制产品的创建、销毁、缓存如连接池、线程池。解耦创建与使用使用者无需关心产品实现细节仅依赖抽象接口如框架开发、跨模块协作。产品族关联场景存在多个相关联的产品需保证兼容性如 UI 主题、电子设备套装。5.2 反场景不建议使用简单对象创建产品创建仅需new关键字无复杂逻辑如std::string实例使用工厂会增加不必要的复杂度。产品类型极少且固定无需扩展简单new即可满足需求如工具类的单一实例。需直接控制对象构造使用者需灵活调整产品的构造参数、初始化顺序工厂的封装会限制灵活性。过度设计风险为了“用设计模式”而强行使用工厂导致系统复杂度上升如小型项目的简单组件。六、C 成熟库中的工厂模式应用C 标准库std::make_unique/std::make_shared本质是简单工厂封装了智能指针的创建逻辑。Boost 库boost::factory提供通用工厂模板支持灵活配置产品创建逻辑避免重复编写工厂代码。Qt 框架QFactoryLoader是抽象工厂的典型应用用于加载插件如 Qt 风格插件、图像格式插件通过插件名创建对应产品。数据库连接池如MySQL Connector/C中的连接工厂根据配置创建不同类型的数据库连接MySQL、Oracle。七、总结与核心原则工厂模式的核心是“封装创建解耦依赖”三种类型从简单到复杂覆盖不同场景简单工厂简洁优先适合产品少的场景工厂方法扩展优先适合产品多的场景抽象工厂产品族优先适合关联产品的场景。核心原则优先依赖抽象使用者仅依赖抽象产品和抽象工厂不依赖具体实现。避免过度设计根据实际场景选择最简单的工厂模式无需盲目追求复杂扩展。结合 C 特性使用智能指针管理内存、单例模式优化工厂、模板简化工厂代码。遵守设计原则工厂模式的设计需符合开闭原则、单一职责原则、依赖倒置原则确保系统可维护、可扩展。在实际开发中工厂模式是最常用的创建型设计模式之一掌握其核心思想和实现技巧能有效提升代码的灵活性、可维护性尤其在框架开发、组件化设计中发挥重要作用。

更多文章