C++ 设计模式之工厂模式详细介绍

工厂模式是 创建型设计模式 的核心成员,其核心目标是:封装对象的创建过程,将对象创建与使用逻辑解耦,通过统一的"工厂"接口创建不同类型的对象,无需暴露对象的具体创建细节。

在 C++ 开发中,工厂模式广泛应用于对象创建逻辑复杂、产品类型多变、需要统一管理对象生命周期的场景(如框架组件、插件系统、数据库连接池、UI 组件库等)。根据封装程度和适用场景,工厂模式分为三类:简单工厂模式工厂方法模式抽象工厂模式,三者是"从简单到复杂、从单一到多样"的递进关系。

一、工厂模式的核心目标与设计思想

1.1 核心目标

  1. 封装创建逻辑:将对象的创建细节(如构造参数、初始化步骤、依赖注入)隐藏在工厂类中,使用者无需关心"如何创建",只需调用工厂接口即可。
  2. 解耦创建与使用:使用者仅依赖产品的抽象接口(而非具体实现),修改产品实现或新增产品时,无需修改使用代码(符合"开闭原则")。
  3. 统一管理对象:通过工厂集中控制对象的创建、初始化、销毁,便于添加日志、缓存、权限校验等统一逻辑。
  4. 支持灵活扩展:新增产品时,只需扩展工厂或新增具体工厂,无需修改现有代码。

1.2 核心设计思想

  • 依赖倒置原则:依赖抽象(产品接口、工厂接口),不依赖具体实现(具体产品、具体工厂)。
  • 里氏替换原则:具体产品可替换抽象产品,具体工厂可替换抽象工厂,不影响使用逻辑。
  • 单一职责原则:工厂类仅负责对象创建,产品类仅负责业务逻辑,各司其职。

二、工厂模式的三种核心类型(含 C++ 实现)

2.1 简单工厂模式(Simple Factory Pattern)

定义

由一个 单一工厂类 负责所有产品的创建,通过传入参数(如类型标识),工厂类动态决定创建哪种具体产品。本质是"集中式创建",将所有产品的创建逻辑封装在一个工厂中。

结构组成
  1. 抽象产品(Product):所有具体产品的基类(通常是抽象类/接口,含纯虚函数定义核心业务方法)。
  2. 具体产品(ConcreteProduct):抽象产品的实现类,包含具体业务逻辑。
  3. 工厂类(Factory):核心类,提供静态或成员方法,根据参数创建并返回具体产品的指针/引用。
C++ 实现代码
cpp 复制代码
#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_ptr<Shape> createShape(const std::string& type) {
        if (type == "circle") {
            return std::make_unique<Circle>();
        } else if (type == "rectangle") {
            return std::make_unique<Rectangle>();
        } else if (type == "triangle") {
            return std::make_unique<Triangle>();
        } 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)
错误:不支持的形状类型:square
核心优点
  • 实现简单:仅需一个工厂类,代码量少,易于理解和维护。
  • 封装性好:使用者无需知道产品的创建细节,只需传入类型参数。
  • 统一管理:产品创建逻辑集中在工厂,便于添加日志、缓存等扩展逻辑。
核心缺点
  • 违反开闭原则 :新增产品时,必须修改工厂类的 createShape 方法(添加新的 if-else),导致工厂类逐渐臃肿。
  • 工厂类职责过重:所有产品的创建逻辑都在一个工厂中,一旦工厂出错,所有产品创建都会受影响。
  • 扩展性差 :产品类型过多时,if-else 分支会变得冗长,维护困难。
适用场景
  • 产品类型较少(如 3-5 种),且不常新增产品。
  • 简单场景,无需复杂的扩展机制(如小型工具类、简单组件创建)。

2.2 工厂方法模式(Factory Method Pattern)

定义

为解决简单工厂的"开闭原则"问题,将 单一工厂拆分为多个具体工厂:每个具体产品对应一个具体工厂,抽象出统一的工厂接口,新增产品时只需新增"具体产品 + 具体工厂",无需修改现有代码。本质是"分拆式创建",将创建职责分散到各个具体工厂。

结构组成
  1. 抽象产品(Product):所有具体产品的基类(抽象类/接口)。
  2. 具体产品(ConcreteProduct):抽象产品的实现类。
  3. 抽象工厂(AbstractFactory) :所有具体工厂的基类(抽象类/接口),含纯虚函数 createProduct()(定义产品创建接口)。
  4. 具体工厂(ConcreteFactory):抽象工厂的实现类,每个具体工厂仅负责创建一种具体产品。
C++ 实现代码
cpp 复制代码
#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_ptr<Shape> createShape() const = 0;  // 纯虚函数,子类实现
};

// 4. 具体工厂:圆形工厂(仅创建圆形)
class CircleFactory : public ShapeFactory {
public:
    std::unique_ptr<Shape> createShape() const override {
        return std::make_unique<Circle>();
    }
};

// 具体工厂:矩形工厂(仅创建矩形)
class RectangleFactory : public ShapeFactory {
public:
    std::unique_ptr<Shape> createShape() const override {
        return std::make_unique<Rectangle>();
    }
};

// 测试代码:使用者依赖抽象工厂和抽象产品,可灵活替换具体工厂
int main() {
    // 圆形工厂创建圆形
    std::unique_ptr<ShapeFactory> circleFactory = std::make_unique<CircleFactory>();
    auto circle = circleFactory->createShape();
    circle->draw();

    // 矩形工厂创建矩形
    std::unique_ptr<ShapeFactory> rectFactory = std::make_unique<RectangleFactory>();
    auto rectangle = rectFactory->createShape();
    rectangle->draw();

    // 新增产品(如三角形):仅需添加 Triangle 类和 TriangleFactory 类,无需修改现有代码
    return 0;
}
输出结果
复制代码
绘制圆形(Circle)
绘制矩形(Rectangle)
核心优点
  • 符合开闭原则:新增产品时,只需新增"具体产品 + 具体工厂",无需修改现有工厂和使用代码。
  • 职责单一:每个具体工厂仅负责创建一种产品,工厂类职责清晰,维护简单。
  • 扩展性强:支持灵活替换具体工厂(如替换不同的产品实现),符合里氏替换原则。
核心缺点
  • 类数量膨胀:每新增一个产品,需同时新增一个具体工厂类,导致系统中类的数量增多,复杂度上升。
  • 逻辑分散:创建逻辑分散在多个具体工厂中,如需统一修改创建逻辑(如添加日志),需修改所有具体工厂。
  • 使用成本高 :使用者需知道具体工厂和具体产品的对应关系(如创建圆形需用 CircleFactory),不像简单工厂那样只需传入参数。
适用场景
  • 产品类型较多,且频繁新增产品(如插件系统、组件库)。
  • 需灵活替换产品实现(如不同数据库的连接工厂:MySQLFactory、OracleFactory)。
  • 要求严格遵守开闭原则的场景(如框架开发)。

2.3 抽象工厂模式(Abstract Factory Pattern)

定义

当系统中存在 多个相关联的产品族(而非单一产品)时,抽象工厂模式定义一个"产品族工厂接口",每个具体工厂负责创建一个完整的产品族(多个相关产品)。本质是"产品族级别的创建",解决"一系列相关产品的统一创建"问题。

关键概念
  • 产品族:一组相关联的产品(如"华为产品族"包含华为手机、华为耳机;"苹果产品族"包含苹果手机、苹果耳机)。
  • 产品等级结构:同一类型的产品(如手机是一个产品等级,耳机是另一个产品等级)。
结构组成
  1. 抽象产品族:多个抽象产品(每个产品等级对应一个抽象产品)。
  2. 具体产品族:多个具体产品,每个具体产品属于一个产品等级,且归属于某个产品族。
  3. 抽象工厂:定义创建所有产品等级的接口(每个产品等级对应一个创建方法)。
  4. 具体工厂:实现抽象工厂接口,创建对应产品族的所有产品(如华为工厂创建华为手机、华为耳机)。
C++ 实现代码
cpp 复制代码
#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_ptr<Phone> createPhone() const = 0;
    virtual std::unique_ptr<Headphone> createHeadphone() const = 0;
};

// 4. 具体工厂1:华为工厂(创建华为产品族的所有产品)
class HuaweiFactory : public ElectronicFactory {
public:
    std::unique_ptr<Phone> createPhone() const override {
        return std::make_unique<HuaweiPhone>();
    }

    std::unique_ptr<Headphone> createHeadphone() const override {
        return std::make_unique<HuaweiHeadphone>();
    }
};

// 具体工厂2:苹果工厂(创建苹果产品族的所有产品)
class AppleFactory : public ElectronicFactory {
public:
    std::unique_ptr<Phone> createPhone() const override {
        return std::make_unique<IPhone>();
    }

    std::unique_ptr<Headphone> createHeadphone() const override {
        return std::make_unique<AirPods>();
    }
};

// 测试代码:使用者通过具体工厂获取完整的产品族
int main() {
    // 华为工厂:创建华为手机 + 华为耳机
    std::unique_ptr<ElectronicFactory> huaweiFactory = std::make_unique<HuaweiFactory>();
    auto huaweiPhone = huaweiFactory->createPhone();
    auto huaweiHeadphone = huaweiFactory->createHeadphone();
    std::cout << "华为产品族:" << huaweiPhone->getName() << " + " << huaweiHeadphone->getName() << std::endl;

    // 苹果工厂:创建苹果手机 + 苹果耳机
    std::unique_ptr<ElectronicFactory> appleFactory = std::make_unique<AppleFactory>();
    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 2
核心优点
  • 统一产品族创建:一个具体工厂对应一个完整的产品族,确保产品族内的产品兼容性(如华为手机和华为耳机可联动)。
  • 符合开闭原则:新增产品族时,只需新增"具体产品族 + 具体工厂",无需修改现有代码。
  • 封装性更强:使用者无需知道产品族内各产品的创建细节,只需通过工厂获取整套产品。
核心缺点
  • 扩展产品等级困难:若需新增产品等级(如在"手机+耳机"基础上新增"平板"),需修改抽象工厂接口和所有具体工厂,违反开闭原则。
  • 复杂度高:系统中存在多个抽象产品和具体产品,类结构复杂,理解和维护成本高。
  • 初始化成本高:具体工厂需创建产品族的所有产品,若产品族较大,初始化开销较高。
适用场景
  • 系统中存在多个相关联的产品族(如电子设备、UI 组件主题、数据库驱动+连接池)。
  • 需确保产品族内产品兼容性的场景(如同一主题的按钮、输入框、下拉框)。
  • 不常新增产品等级,但可能新增产品族的场景(如框架的多主题支持)。

三、三种工厂模式的对比与选择

特性 简单工厂模式 工厂方法模式 抽象工厂模式
核心定位 单一工厂创建所有产品 一个产品对应一个工厂 一个产品族对应一个工厂
开闭原则兼容性 违反(新增产品需改工厂) 符合(新增产品加工厂) 符合产品族,违反产品等级
类数量 少(1 工厂 + N 产品) 中(N 工厂 + N 产品) 多(N 工厂 + M*N 产品)
适用场景 产品少、不常扩展 产品多、常扩展 存在产品族、需保证兼容性
使用者复杂度 低(仅传参数) 中(需知道工厂-产品对应关系) 高(需理解产品族概念)
扩展成本 低(修改工厂) 中(新增工厂+产品) 产品族扩展低,产品等级扩展高

选择建议

  1. 优先选简单工厂:若产品类型少(≤5 种)、不常新增,简单工厂的简洁性是最优选择。
  2. 选工厂方法:若产品类型多、需频繁新增,且无产品族关联,工厂方法的扩展性更优。
  3. 选抽象工厂:若存在多个相关联的产品族(如主题、设备套装),需保证产品兼容性,抽象工厂是唯一选择。

四、C++ 工厂模式的关键实现技巧

4.1 内存管理:使用智能指针避免泄漏

工厂模式中,产品通常通过 new 创建,手动管理内存易导致泄漏。C++11 后推荐使用 智能指针std::unique_ptr/std::shared_ptr):

  • std::unique_ptr:独占所有权,适合产品生命周期由使用者管理的场景(如示例代码)。
  • std::shared_ptr:共享所有权,适合产品需被多个模块共享的场景(如缓存中的产品实例)。

4.2 工厂的单例化

工厂类本身通常无需多个实例(创建产品的逻辑是固定的),可将工厂设计为单例(如 Meyers 单例),减少实例创建开销:

cpp 复制代码
// 单例工厂(以简单工厂为例)
class ShapeFactory {
public:
    static ShapeFactory& getInstance() {
        static ShapeFactory instance;
        return instance;
    }

    std::unique_ptr<Shape> 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 产品初始化参数传递

若产品需要构造参数(如配置信息),可在工厂方法中添加参数:

cpp 复制代码
// 抽象产品:带参数初始化的数据库连接
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_ptr<DBConnection> createConnection(
        const std::string& host, int port, const std::string& dbName) const {
        return std::make_unique<MySQLConnection>(host, port, dbName);
    }
};

// 使用
auto mysqlConn = MySQLFactory().createConnection("127.0.0.1", 3306, "test_db");
mysqlConn->connect();

4.4 工厂的延迟初始化与缓存

对于创建成本高的产品(如数据库连接、重型组件),可在工厂中添加缓存机制,复用已创建的实例:

cpp 复制代码
class ShapeFactory {
public:
    std::shared_ptr<Shape> 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_map<std::string, std::shared_ptr<Shape>> cache_;  // 产品缓存
    // createShape 方法...
};

五、工厂模式的适用场景与反场景

5.1 适用场景

  1. 对象创建逻辑复杂:产品创建需多步初始化、依赖外部资源(如配置文件、网络连接),或需校验参数。
  2. 产品类型多变:需频繁新增产品(如插件系统、组件库),或替换产品实现(如不同数据库驱动)。
  3. 需要统一管理对象:需集中控制产品的创建、销毁、缓存(如连接池、线程池)。
  4. 解耦创建与使用:使用者无需关心产品实现细节,仅依赖抽象接口(如框架开发、跨模块协作)。
  5. 产品族关联场景:存在多个相关联的产品,需保证兼容性(如 UI 主题、电子设备套装)。

5.2 反场景(不建议使用)

  1. 简单对象创建 :产品创建仅需 new 关键字,无复杂逻辑(如 std::string 实例),使用工厂会增加不必要的复杂度。
  2. 产品类型极少且固定 :无需扩展,简单 new 即可满足需求(如工具类的单一实例)。
  3. 需直接控制对象构造:使用者需灵活调整产品的构造参数、初始化顺序,工厂的封装会限制灵活性。
  4. 过度设计风险:为了"用设计模式"而强行使用工厂,导致系统复杂度上升(如小型项目的简单组件)。

六、C++ 成熟库中的工厂模式应用

  1. C++ 标准库std::make_unique/std::make_shared 本质是简单工厂,封装了智能指针的创建逻辑。
  2. Boost 库boost::factory 提供通用工厂模板,支持灵活配置产品创建逻辑,避免重复编写工厂代码。
  3. Qt 框架QFactoryLoader 是抽象工厂的典型应用,用于加载插件(如 Qt 风格插件、图像格式插件),通过插件名创建对应产品。
  4. 数据库连接池 :如 MySQL Connector/C++ 中的连接工厂,根据配置创建不同类型的数据库连接(MySQL、Oracle)。

七、总结与核心原则

工厂模式的核心是 "封装创建,解耦依赖",三种类型从简单到复杂,覆盖不同场景:

  • 简单工厂:简洁优先,适合产品少的场景;
  • 工厂方法:扩展优先,适合产品多的场景;
  • 抽象工厂:产品族优先,适合关联产品的场景。

核心原则

  1. 优先依赖抽象:使用者仅依赖抽象产品和抽象工厂,不依赖具体实现。
  2. 避免过度设计:根据实际场景选择最简单的工厂模式,无需盲目追求复杂扩展。
  3. 结合 C++ 特性:使用智能指针管理内存、单例模式优化工厂、模板简化工厂代码。
  4. 遵守设计原则:工厂模式的设计需符合开闭原则、单一职责原则、依赖倒置原则,确保系统可维护、可扩展。

在实际开发中,工厂模式是最常用的创建型设计模式之一,掌握其核心思想和实现技巧,能有效提升代码的灵活性、可维护性,尤其在框架开发、组件化设计中发挥重要作用。

相关推荐
想要成为祖国的花朵1 小时前
基于多设计模式的抽奖系统__测试报告
java·selenium·测试工具·jmeter·设计模式·测试用例·安全性测试
胖咕噜的稞达鸭1 小时前
算法入门:专题二分查找算法 模板总结 题目练手 :排序数组中查找元素的第一个和最后一个位置 第一个错误的版本 查找x的平方根 搜索插入位置 山脉数组的封顶索引
c语言·c++·算法·leetcode
Linux技术芯1 小时前
浅谈scsi协议的命令描述符CDB工作原理
linux
松涛和鸣1 小时前
21、单向链表完整实现与核心技巧总结
linux·c语言·数据结构·算法·链表
人工智能训练1 小时前
Docker中Dify镜像由Windows系统迁移到Linux系统的方法
linux·运维·服务器·人工智能·windows·docker·dify
未来之窗软件服务1 小时前
幽冥大陆(三十六)S18酒店门锁SDK rust语言——东方仙盟筑基期
开发语言·c++·rust·智能门锁·东方仙盟sdk·东方仙盟一体化
君以思为故1 小时前
认识linux -- 进程控制
linux·运维·1024程序员节
Mr.H01271 小时前
深入理解高级IO:从模型到实战,实现高性能并发服务器
linux·服务器·网络·tcp/ip·php
v***5651 小时前
常见的 Spring 项目目录结构
java·后端·spring