设计模式:工厂模式(Factory Pattern)

一、工厂模式简介

  工厂模式是一种创建型设计模式,主要解决对象创建 的问题。它的核心思想是:把对象的创建和使用分离,让使用者不直接依赖具体类,而是通过工厂来获得对象。

常见的工厂模式有三种:

  1. 简单工厂模式(Simple Factory) —— 一个工厂类,通过传入参数决定创建哪种产品对象。
  2. 工厂方法模式(Factory Method) —— 将工厂抽象化,不同子工厂创建不同的产品对象。
  3. 抽象工厂模式(Abstract Factory) —— 一个工厂可以创建一组相关的产品对象。

工厂方法模式结构:
在这里插入图片描述

二、简单工厂模式的概念

它的核心思想是:由一个工厂类决定创建哪一种具体产品对象。
特点:

  • 有一个抽象产品基类(或接口)。
  • 有多个具体产品类(继承自产品基类)。
  • 有一个工厂类,通过传入参数来决定实例化哪个产品。

使用场景:

  • 产品种类较少;
  • 对象创建逻辑不复杂;
  • 需要屏蔽对象创建细节,让用户专注于使用。

结构图:

          +----------------+
          |   Product      |<----- 抽象产品
          +----------------+
                  ^
       ---------------------------
       |                         |
+---------------+        +---------------+
|   ProductA    |        |   ProductB    |   <-- 具体产品
+---------------+        +---------------+

          +----------------+
          | SimpleFactory  |   <-- 工厂类
          +----------------+
          | createProduct()|
          +----------------+

该模式对对象创建管理方式最为简单,因为其仅仅简单的对不同类对象的创建进行了一层薄薄的封装。该模式通过向工厂传递类型来指定要创建的对象,其UML类图如下:
在这里插入图片描述

示例代码:

#include <iostream>
#include <memory>
using namespace std;

// 1. 抽象产品
class Product {
public:
    virtual void show() = 0;
    virtual ~Product() = default;
};

// 2. 具体产品 A
class ProductA : public Product {
public:
    void show() override {
        cout << "This is Product A" << endl;
    }
};

// 3. 具体产品 B
class ProductB : public Product {
public:
    void show() override {
        cout << "This is Product B" << endl;
    }
};

// 4. 工厂类
class SimpleFactory {
public:
    static unique_ptr<Product> createProduct(const string& type) {
        if (type == "A") {
            return make_unique<ProductA>();
        } else if (type == "B") {
            return make_unique<ProductB>();
        }
        return nullptr;
    }
};

// 5. 客户端使用
int main() {
    auto p1 = SimpleFactory::createProduct("A");
    auto p2 = SimpleFactory::createProduct("B");

    if (p1) p1->show();
    if (p2) p2->show();

    return 0;
}

优点
封装对象创建:

  • 客户端不需要知道具体类名,只需要传入参数即可。
  • 创建和使用分离,降低耦合度。

易于维护

  • 修改产品创建逻辑时只需改动工厂,不影响客户端代码。

缺点
违背开闭原则(OCP):

  • 新增产品时需要修改工厂代码(新增 else if)。
  • 工厂类会越来越臃肿。

不够灵活:

  • 所有产品都集中到一个工厂,不利于扩展和维护。

使用场景:

  • 小型项目,产品种类不多;
  • 只需要一个工厂类管理对象创建;
  • 对象创建过程可能包含一些额外逻辑(如日志、权限、缓存)。

例如:

  • 数据库连接工厂:根据配置文件创建 MySQL 或 SQLite 连接;
  • 图形界面控件工厂:根据字符串返回不同控件对象;
  • 多媒体播放器:根据文件扩展名返回不同解码器对象。

简单工厂模式的具体实例
场景:
统需要支持不同品牌的 NVR(大华、海康、TP-LINK),但客户端代码不应该直接依赖具体品牌类,而是通过一个统一的接口来操作。

实现步骤:
1. 定义抽象产品接口

// NVR抽象接口
class INvr {
public:
    virtual ~INvr() {}
    virtual void connect() = 0;
    virtual void preview() = 0;
};

2. 定义具体产品

#include <QDebug>

// 大华NVR
class DahuaNvr : public INvr {
public:
    void connect() override { qDebug() << "连接大华 NVR 成功"; }
    void preview() override { qDebug() << "大华 NVR 正在实时预览"; }
};

// 海康NVR
class HikvisionNvr : public INvr {
public:
    void connect() override { qDebug() << "连接海康 NVR 成功"; }
    void preview() override { qDebug() << "海康 NVR 正在实时预览"; }
};

// TP-LINK NVR
class TpLinkNvr : public INvr {
public:
    void connect() override { qDebug() << "连接 TP-LINK NVR 成功"; }
    void preview() override { qDebug() << "TP-LINK NVR 正在实时预览"; }
};

3. 工厂类(简单工厂)

class NvrFactory {
public:
    static INvr* createNvr(const QString& type) {
        if (type == "Dahua") {
            return new DahuaNvr();
        } else if (type == "Hikvision") {
            return new HikvisionNvr();
        } else if (type == "TP-Link") {
            return new TpLinkNvr();
        }
        return nullptr;
    }
};

4. 客户端使用

int main() {
    // 客户端只需要告诉工厂想要哪个品牌的NVR
    INvr* nvr = NvrFactory::createNvr("Hikvision");

    if (nvr) {
        nvr->connect();
        nvr->preview();
        delete nvr; // 注意释放资源
    }
    return 0;
}

优点:

  • 客户端只依赖 抽象接口,无需关心具体产品类。
  • 创建逻辑集中在工厂类,便于维护。

缺点:

  • 不符合开闭原则:如果增加新品牌 NVR,需要修改工厂类的 createNvr() 代码。更复杂场景就要用 工厂方法模式 或 抽象工厂模式。

三、工厂方法模式的概念

它的核心思想是:将对象的创建延迟到子类中,由子类工厂来决定实例化哪个具体产品。

区别于 简单工厂模式:

  • 简单工厂模式:一个工厂类负责所有产品的创建 → 新增产品时需要修改工厂类(不符合开闭原则)。
  • 工厂方法模式:每个产品对应一个工厂类 → 新增产品时只需增加新的工厂类,无需修改已有工厂。

模式结构:

         +------------------+
         |   Product        |<----- 抽象产品
         +------------------+
         | + operation()    |
         +------------------+
                  ^
     -----------------------------
     |                           |
+-------------+          +---------------+
| ProductA    |          | ProductB      | <-- 具体产品
+-------------+          +---------------+


         +------------------+
         |  Factory         |<----- 抽象工厂
         +------------------+
         | + createProduct()|
         +------------------+
                  ^
     -----------------------------
     |                           |
+---------------+       +---------------+
| FactoryA      |       | FactoryB      | <-- 具体工厂
+---------------+       +---------------+

该模式对对象创建管理方式最为简单,因为其仅仅简单的对不同类对象的创建进行了一层薄薄的封装。该模式通过向工厂传递类型来指定要创建的对象,其UML类图如下:
在这里插入图片描述
示例代码:

#include <iostream>
#include <memory>
using namespace std;

// 1. 抽象产品
class Product {
public:
    virtual void operation() = 0;
    virtual ~Product() = default;
};

// 2. 具体产品 A
class ProductA : public Product {
public:
    void operation() override {
        cout << "Product A operation" << endl;
    }
};

// 3. 具体产品 B
class ProductB : public Product {
public:
    void operation() override {
        cout << "Product B operation" << endl;
    }
};

// 4. 抽象工厂
class Factory {
public:
    virtual unique_ptr<Product> createProduct() = 0;
    virtual ~Factory() = default;
};

// 5. 具体工厂 A
class FactoryA : public Factory {
public:
    unique_ptr<Product> createProduct() override {
        return make_unique<ProductA>();
    }
};

// 6. 具体工厂 B
class FactoryB : public Factory {
public:
    unique_ptr<Product> createProduct() override {
        return make_unique<ProductB>();
    }
};

// 7. 客户端
int main() {
    unique_ptr<Factory> factoryA = make_unique<FactoryA>();
    auto productA = factoryA->createProduct();
    productA->operation();

    unique_ptr<Factory> factoryB = make_unique<FactoryB>();
    auto productB = factoryB->createProduct();
    productB->operation();

    return 0;
}

优点:

  1. 符合 开闭原则:新增产品时,只需新增具体产品类和对应工厂类,不改动已有代码。
  2. 将对象创建逻辑下放到具体工厂,解耦了“使用者”和“产品创建者”。
  3. 客户端只依赖抽象接口,增强可扩展性。

缺点:

  • 每新增一个产品,就需要新增一个工厂类,类数量增加,结构更复杂。
  • 如果产品种类非常多,可能会带来额外的维护成本。

适用场景:

  • 系统需要满足 开闭原则,频繁扩展产品。
  • 不同的产品创建过程可能有一定差异,不能集中放在一个简单工厂里。

例如:

  • 不同品牌数据库连接(MySQLFactory、SQLiteFactory…)。
  • 不同类型日志记录器(FileLoggerFactory、ConsoleLoggerFactory…)。
  • 不同 NVR 接入厂商(DahuaFactory、HikvisionFactory、TplinkFactory…)。

工厂方法模式的具体实例
相比 简单工厂模式,工厂方法模式的关键点是:

  • 不再由一个工厂类统一生产所有产品;
  • 而是每个产品有一个对应的工厂类;
  • 这样当你新增一个 NVR 厂商时,不需要修改已有工厂,只需新增对应的工厂类,符合 开闭原则。

实现步骤:
1. 定义抽象产品接口

// NVR 抽象接口
class INvr {
public:
    virtual ~INvr() {}
    virtual void connect() = 0;
    virtual void preview() = 0;
};

2. 定义具体产品

#include <QDebug>

// 大华NVR
class DahuaNvr : public INvr {
public:
    void connect() override { qDebug() << "连接大华 NVR 成功"; }
    void preview() override { qDebug() << "大华 NVR 正在实时预览"; }
};

// 海康NVR
class HikvisionNvr : public INvr {
public:
    void connect() override { qDebug() << "连接海康 NVR 成功"; }
    void preview() override { qDebug() << "海康 NVR 正在实时预览"; }
};

// TP-LINK NVR
class TpLinkNvr : public INvr {
public:
    void connect() override { qDebug() << "连接 TP-LINK NVR 成功"; }
    void preview() override { qDebug() << "TP-LINK NVR 正在实时预览"; }
};

3. 定义工厂接口

// 工厂接口
class INvrFactory {
public:
    virtual ~INvrFactory() {}
    virtual INvr* createNvr() = 0;
};

4. 定义具体工厂

// 大华工厂
class DahuaFactory : public INvrFactory {
public:
    INvr* createNvr() override {
        return new DahuaNvr();
    }
};

// 海康工厂
class HikvisionFactory : public INvrFactory {
public:
    INvr* createNvr() override {
        return new HikvisionNvr();
    }
};

// TP-LINK 工厂
class TpLinkFactory : public INvrFactory {
public:
    INvr* createNvr() override {
        return new TpLinkNvr();
    }
};

5. 客户端使用

int main() {
    // 客户端只依赖工厂接口,不依赖具体NVR实现
    INvrFactory* factory = new HikvisionFactory();
    INvr* nvr = factory->createNvr();

    nvr->connect();
    nvr->preview();

    delete nvr;
    delete factory;

    return 0;
}

优点:

  • 新增品牌时只需 新增产品类和工厂类,无需修改已有代码,符合 开闭原则。
  • 客户端只依赖抽象接口,扩展性强。

缺点:

  • 类的数量会增加(每个产品都要有一个对应工厂)。
  • 如果品牌很多,工厂类会比较多。

四、抽象工厂模式的概念

它提供一个 接口,用于创建一族相关或相互依赖的对象,而不需要指定它们的具体类。

关键点:

  • 一族(family):一整套相互关联的产品,例如按钮 + 文本框。
  • 工厂提供统一的接口,保证创建的对象属于同一系列。

适用场景:

  1. 存在多个产品族,而客户端只使用其中一个。例:Windows、Mac、Linux 的 UI 控件库。
  2. 系统需要保证同一产品族的对象一起使用,防止混搭。Windows 按钮 + Mac 文本框(风格冲突)。

模式结构:

 抽象产品
+-----------+    +-----------+
|  Button   |    | TextBox   |
+-----------+    +-----------+
     ^                 ^
     |                 |
+-----------+    +-----------+
| WinButton |    | WinTextBox|
+-----------+    +-----------+
| MacButton |    | MacTextBox|
+-----------+    +-----------+

 抽象工厂
+----------------+
|  GUIFactory    |
+----------------+
|+createButton() |
|+createTextBox()|
+----------------+
       ^
       |
 -------------------------
 |                       |
+-------------+   +-------------+
| WinFactory  |   | MacFactory  |
+-------------+   +-------------+

抽象工厂模式通过在AbstarctFactory中增加创建产品的接口,并在具体子工厂中实现新加产品的创建,当然前提是子工厂支持生产该产品。否则继承的这个接口可以什么也不干。其UML类图如下:
在这里插入图片描述
示例代码:

#include <iostream>
#include <memory>
using namespace std;

// 抽象产品 - 按钮
class Button {
public:
    virtual void click() = 0;
    virtual ~Button() = default;
};

// 抽象产品 - 文本框
class TextBox {
public:
    virtual void show() = 0;
    virtual ~TextBox() = default;
};

// Windows 系列产品
class WinButton : public Button {
public:
    void click() override { cout << "Windows Button clicked" << endl; }
};
class WinTextBox : public TextBox {
public:
    void show() override { cout << "Windows TextBox show" << endl; }
};

// Mac 系列产品
class MacButton : public Button {
public:
    void click() override { cout << "Mac Button clicked" << endl; }
};
class MacTextBox : public TextBox {
public:
    void show() override { cout << "Mac TextBox show" << endl; }
};

// 抽象工厂
class GUIFactory {
public:
    virtual unique_ptr<Button> createButton() = 0;
    virtual unique_ptr<TextBox> createTextBox() = 0;
    virtual ~GUIFactory() = default;
};

// Windows 工厂
class WinFactory : public GUIFactory {
public:
    unique_ptr<Button> createButton() override { return make_unique<WinButton>(); }
    unique_ptr<TextBox> createTextBox() override { return make_unique<WinTextBox>(); }
};

// Mac 工厂
class MacFactory : public GUIFactory {
public:
    unique_ptr<Button> createButton() override { return make_unique<MacButton>(); }
    unique_ptr<TextBox> createTextBox() override { return make_unique<MacTextBox>(); }
};

// 客户端
int main() {
    unique_ptr<GUIFactory> factory = make_unique<WinFactory>(); // 可切换为 MacFactory
    auto btn = factory->createButton();
    auto txt = factory->createTextBox();

    btn->click();
    txt->show();

    return 0;
}

优点:

  1. 保证产品族的一致性(不会混搭不同系列)。
  2. 符合开闭原则:新增一个产品族(如 Linux),只需增加一个工厂和对应的产品类。
  3. 客户端只依赖抽象接口,解耦。

缺点:

  1. 如果要新增一个 “下拉框(Dropdown)”,需要修改所有工厂接口。
  2. 系统类数量多,复杂度增加。

抽象工厂模式的具体实例
场景:

  • 系统需要接入不同厂商(大华、海康、TP-LINK)的 NVR 和 Camera;
  • 每个厂商形成一个产品族(NVR + Camera);
  • 客户端只依赖抽象接口,不关心具体实现;
  • 工厂负责创建同一产品族的所有对象。

实现步骤:
1. 定义抽象产品接口

// 抽象 NVR
class INvr {
public:
    virtual ~INvr() {}
    virtual void connect() = 0;
    virtual void preview() = 0;
};

// 抽象 Camera
class ICamera {
public:
    virtual ~ICamera() {}
    virtual void start() = 0;
    virtual void stop() = 0;
};

2. 定义具体产品

#include <QDebug>

// 大华产品族
class DahuaNvr : public INvr {
public:
    void connect() override { qDebug() << "连接大华 NVR 成功"; }
    void preview() override { qDebug() << "大华 NVR 正在实时预览"; }
};
class DahuaCamera : public ICamera {
public:
    void start() override { qDebug() << "大华 Camera 开始采集"; }
    void stop() override { qDebug() << "大华 Camera 停止采集"; }
};

// 海康产品族
class HikvisionNvr : public INvr {
public:
    void connect() override { qDebug() << "连接海康 NVR 成功"; }
    void preview() override { qDebug() << "海康 NVR 正在实时预览"; }
};
class HikvisionCamera : public ICamera {
public:
    void start() override { qDebug() << "海康 Camera 开始采集"; }
    void stop() override { qDebug() << "海康 Camera 停止采集"; }
};

3. 定义抽象工厂

class IDeviceFactory {
public:
    virtual ~IDeviceFactory() {}
    virtual INvr* createNvr() = 0;
    virtual ICamera* createCamera() = 0;
};

4. 定义具体工厂

// 大华工厂
class DahuaFactory : public IDeviceFactory {
public:
    INvr* createNvr() override { return new DahuaNvr(); }
    ICamera* createCamera() override { return new DahuaCamera(); }
};

// 海康工厂
class HikvisionFactory : public IDeviceFactory {
public:
    INvr* createNvr() override { return new HikvisionNvr(); }
    ICamera* createCamera() override { return new HikvisionCamera(); }
};

5. 客户端使用

int main() {
    // 客户端只依赖抽象工厂接口
    IDeviceFactory* factory = new DahuaFactory();

    INvr* nvr = factory->createNvr();
    ICamera* cam = factory->createCamera();

    nvr->connect();
    nvr->preview();

    cam->start();
    cam->stop();

    delete nvr;
    delete cam;
    delete factory;

    return 0;
}

优点:

  • 保证产品族一致性:不会出现大华 NVR + 海康 Camera 混用。
  • 符合开闭原则:新增厂商时只需新增工厂和产品类,不修改客户端。
  • 客户端只依赖抽象接口,完全解耦。

缺点:

  • 扩展产品等级困难:若要新增一个 “存储设备 Storage”,必须修改所有工厂接口。
  • 类数量较多,系统复杂度增加。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值