当前位置: 首页 > news >正文

设计模式:工厂模式

文章目录

    • 一、工厂模式简介
    • 二、简单工厂模式的概念
    • 三、工厂方法模式的概念
    • 四、抽象工厂模式的概念

一、工厂模式简介

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

常见的工厂模式有三种:

  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() {// 客户端只需要告诉工厂想要哪个品牌的NVRINvr* 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>(); // 可切换为 MacFactoryauto 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”,必须修改所有工厂接口。
  • 类数量较多,系统复杂度增加。
http://www.dtcms.com/a/347983.html

相关文章:

  • 3.4 磁盘存储器 (答案见原书 P194)
  • STM32H723Zx OCTO-SPI(OSPI) 读写 W25Q64
  • fastmcp 客服端远程MCP服务调用;多工具 MCP服务情景案例;集成fastapi服务
  • Vue.js 核心机制深度学习笔记
  • 阿里云 OSS 前端直传实战:表单上传 + Policy 模式详解
  • 基于魔搭社区与阿里云百炼的云端 RAG 私有知识问答系统实现
  • GHOST 小巧方便的 WinXP !
  • 华为网路设备学习-30(BGP协议 五)Community、
  • 【重学MySQL】八十八、8.0版本核心新特性全解析
  • 质量管理与项目管理学习-初识1
  • ThinkPHP8学习篇(四):请求和响应
  • 基于FPGA的情绪感知系统设计方案:心理健康监测应用(一)
  • centos搭建gitlab服务器
  • 【R语言】R语言中 rbind() 与 merge() 的区别详解
  • 【企业标准开发框架 01】全局异常处理+自定义异常类
  • JAVA限流方法
  • System.IO.Pipelines 与“零拷贝”:在 .NET 打造高吞吐二进制 RPC
  • 【SpringBoot集成篇】SpringBoot 深度集成 Elasticsearch 搜索引擎指南
  • rust语言 (1.88) egui (0.32.1) 学习笔记(逐行注释)(十五)网格布局
  • rust语言 (1.88) egui (0.32.1) 学习笔记(逐行注释)(十三)菜单、右键菜单
  • 【JavaEE】了解synchronized
  • 大数据毕业设计选题推荐-基于大数据的丙型肝炎患者数据可视化分析系统-Hadoop-Spark-数据可视化-BigData
  • 【数据结构】从基础到实战:全面解析归并排序与计数排序
  • 基于stm32汽车雨刮器控制系统设计
  • Java基础第3天总结(面向对象)
  • Shell Case 条件语句详解
  • EP01:【DA】数据分析的概述
  • 01Shell脚本入门:基础命令与变量解析
  • JVM之【类加载系统】
  • 【Qt开发】常用控件(六)