【设计模式】抽象工厂模式(含与工厂方法模式的对比)

news2025/4/2 5:30:15

本期我们来学习一下设计模式之抽象工厂模式,在软件开发中,工厂模式抽象工厂模式 都用于创建对象,但它们的应用场景和实现方式有所不同。本文将基于 C++ 代码,分析抽象工厂模式的实现,并对比其与工厂方法模式的区别。


1. 抽象工厂模式简介

抽象工厂模式(Abstract Factory Pattern)创建型设计模式,用于创建一系列相关或相互依赖的对象,而无需指定其具体类。它提供了一个接口,允许客户端通过工厂方法创建不同类型的对象,而无需关心具体实现。

适用场景

  • 当系统需要创建一系列相关的产品(例如同一风格的桌子和椅子)。
  • 希望确保不同产品之间的兼容性(即,现代风格的桌子应当搭配现代风格的椅子)。
  • 隐藏对象创建的细节,并遵循开放封闭原则

2. 代码分析:抽象工厂模式

我们先看一下接下来实现的示例代码UML图:
抽象工厂UML图

(1) 产品接口

我们定义了**椅子(Chair)桌子(Desk)**两个产品接口,并为它们的不同风格(现代、维多利亚)提供具体实现。

class Chair {
public:
  virtual ~Chair() {}
  virtual std::string SitOn() const = 0; // 坐在椅子上的行为
};

class ModernChair : public Chair {
public:
  std::string SitOn() const override {
    return "Sitting on a modern chair.";
  }
};

class VictorianChair : public Chair {
public:
  std::string SitOn() const override {
    return "Sitting on a Victorian chair.";
  }
};

类似地,我们定义了**桌子(Desk)**接口:

class Desk {
public:
  virtual ~Desk() {}
  virtual std::string WorkOn() const = 0; // 在桌子上工作的行为
  virtual std::string PairWithChair(const Chair &collaborator) const = 0; // 桌子与椅子配对
};

每种桌子都可以与同风格的椅子进行搭配:

class ModernDesk : public Desk {
public:
  std::string WorkOn() const override {
    return "Working on a modern desk.";
  }
  std::string PairWithChair(const Chair &collaborator) const override {
    return "Pairing modern desk with ( " + collaborator.SitOn() + " )";
  }
};

(2) 抽象工厂接口

class AbstractFactory {
public:
  virtual Chair *CreateChair() const = 0;
  virtual Desk *CreateDesk() const = 0;
  virtual ~AbstractFactory() {}
};

这个接口定义了创建相关产品的方法。

(3) 具体工厂

具体工厂负责生产特定风格的家具:

class ModernFurnitureFactory : public AbstractFactory {
public:
  Chair *CreateChair() const override {
    return new ModernChair();
  }
  Desk *CreateDesk() const override {
    return new ModernDesk();
  }
};
class VictorianFurnitureFactory : public AbstractFactory {
public:
  Chair *CreateChair() const override {
    return new VictorianChair();
  }
  Desk *CreateDesk() const override {
    return new VictorianDesk();
  }
};

每个工厂都会创建一组相关联的对象(现代风格 or 维多利亚风格)。

(4) 客户端代码

void ClientCode(const AbstractFactory &factory) {
  const Chair *chair = factory.CreateChair();
  const Desk *desk = factory.CreateDesk();
  std::cout << desk->WorkOn() << "\n";
  std::cout << desk->PairWithChair(*chair) << "\n";
  delete chair;
  delete desk;
}

客户端只与抽象工厂接口交互,而不需要知道具体的工厂实现。

int main() {
  ModernFurnitureFactory *f1 = new ModernFurnitureFactory();
  ClientCode(*f1);
  delete f1;

  VictorianFurnitureFactory *f2 = new VictorianFurnitureFactory();
  ClientCode(*f2);
  delete f2;
  return 0;
}

运行结果:

Client: Testing client code with the first factory type:
Working on a modern desk.
Pairing modern desk with ( Sitting on a modern chair. )

Client: Testing the same client code with the second factory type:
Working on a Victorian desk.
Pairing Victorian desk with ( Sitting on a Victorian chair. )

3. 抽象工厂模式 vs. 工厂方法模式

比较项抽象工厂模式工厂方法模式
主要作用创建一系列相关对象仅创建单一对象
产品数量多个相关的产品(如桌子 + 椅子)单个产品
抽象程度提供多个工厂方法仅提供一个工厂方法
耦合性低,所有产品都由一个工厂创建,保证兼容性低,但每个产品类型需要一个工厂
适用场景需要确保产品之间的兼容性,例如 UI 组件仅创建某种特定类型的对象

示例代码对比

工厂方法模式

class ChairFactory {
public:
  static Chair* CreateChair() {
    return new ModernChair(); // 或者 VictorianChair
  }
};

工厂方法模式中,每个工厂只负责创建一个对象,而不是一组相关的对象。

抽象工厂模式

class AbstractFactory {
public:
  virtual Chair *CreateChair() const = 0;
  virtual Desk *CreateDesk() const = 0;
};

抽象工厂模式中,一个工厂负责创建一组产品(例如:现代风格的桌子 + 现代风格的椅子)。


4. 什么时候使用抽象工厂模式?

当多个产品需要搭配使用时

  • 例如 GUI 库中,需要同时创建Windows 风格的按钮、窗口,或者Mac 风格的按钮、窗口

希望减少依赖并保持代码的可扩展性

  • 未来如果要新增 “复古风格家具”,只需创建新的 RetroFurnitureFactory,无需修改原有代码。

保证产品之间的兼容性

  • 例如,现代椅子只能搭配现代桌子,而不能搭配维多利亚桌子。

5. 总结

  • 工厂方法模式 只创建单一产品,而 抽象工厂模式 可以创建一组相关产品
  • 抽象工厂模式的优势 在于确保产品之间的兼容性,并降低客户端对具体类的依赖。
  • 适用于需要生产一系列相关对象的场景,例如 GUI 组件、数据库驱动等。

如果你的需求仅是创建单个对象,可以使用工厂方法模式
如果你的需求是创建多个相互关联的对象,建议使用抽象工厂模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2322774.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IDEA转战Trae AI IED配置

Trae Ai 的前身是vscode IDEA转战Trae AI IED配置 1.安装java相关的插件 2、安装spring相关的插件 3.配置maven环境 打开 Trae AI IDE -> 首选项 -> 设置 -> Editor 设置 ⚠️配置方式有两种 setting.json文件中直接编辑&#xff08;推荐&#xff09;界面设置 方案…

再学:区块链基础与合约初探 EVM与GAS机制

目录 1.区块链是什么 2.remix ​3.账户​ ​4.以太坊三种交易​ 5.EVM 6.以太坊客户端节点 ​7.Gas费用 8.区块链浏览器 1.区块链是什么 只需要检验根节点 Merkel根是否有更改&#xff0c;就不用检查每个交易是否有更改。方便很多。 2.remix 3.账户 如果交易失败的话&…

Nextjs15 - middleware的使用

nextjs 官方文档&#xff08;current branch 对应如下文档&#xff09; Middlewarepath-to-regexp 本专栏内容均可在Github&#xff1a;test_05/Middleware 找到 一、middleware 基本使用 中间件允许您在请求完成之前运行代码。然后&#xff0c;根据传入的请求&#xff0c;您…

边缘计算 vs. 云计算,谁才是工业物联网的未来?

前言 在物联网&#xff08;IoT&#xff09;飞速发展的今天&#xff0c;边缘计算正在彻底改变数据的处理、存储和分析方式。传统的IoT设备数据通常需要发送到云端进行处理&#xff0c;但随着设备数量的激增&#xff0c;这种模式在延迟、带宽和安全性方面暴露出诸多局限。边缘计…

leetcode.189.轮转数组

第一次全反转&#xff0c;第二次反转前k个&#xff0c;第三次反转后n-k个 需要注意的是向又轮转k个时&#xff0c;如果超出数组长度&#xff0c;要对其进行取模运算才是正确的向右轮转个数 class Solution { private:void rotate(vector<int>& nums,int start,int …

OCR 识别案例

OCR 识别案例 注意点&#xff1a;输入图像尺寸比例尽量和参与模型训练的数据集比例相似&#xff0c;识别效果会更好。 1、pytesseract Pytesseract是一个Python的光学字符识别&#xff08;OCR&#xff09;工具&#xff0c;它作为Tesseract OCR引擎的封装&#xff0c;允许你在…

Mybatis配置文件解析(详细)

引言 在了解Mybatis如何帮助客户进行数据的存取后&#xff0c;便对Mybatis的配置文件起了兴趣&#xff0c;在查阅官方文档后&#xff0c;总结了平时能用到的配置&#xff0c;希望能对大家有帮助 1.核心配置文件 主要是指Mybatis-config.xml中 其包含了会深深影响Mybatis行为…

【BFS】《单源、多源 BFS:图搜索算法的双生力量》

文章目录 前言单源BFS例题一、迷宫中离入口最近的出口二、 最小基因变化三、单词接龙四、为高尔夫比赛砍树 多源BFS例题一、 01 矩阵二、飞地的数量三、地图中的最高点四、地图分析 结语 前言 什么是单源、多源BFS算法问题呢&#xff1f; BFS&#xff08;Breadth - First Sear…

【2025】基于springboot+vue的医院在线问诊系统设计与实现(源码、万字文档、图文修改、调试答疑)

基于Spring Boot Vue的医院在线问诊系统设计与实现功能结构图如下&#xff1a; 课题背景 随着互联网技术的飞速发展和人们生活水平的不断提高&#xff0c;传统医疗模式面临着诸多挑战&#xff0c;如患者就医排队时间长、医疗资源分配不均、医生工作压力大等。同时&#xff0c;…

STM32基础教程——PWM驱动舵机

目录 前言 技术实现 原理图 接线图 代码实现 内容要点 PWM基本结构 开启外设时钟 配置GPIO端口 配置时基单元 初始化输出比较单元 调整PWM占空比 输出比较通道重映射 舵机角度设置 实验结果 问题记录 前言 舵机&#xff08;Servo&#xff09;是一种位置&#xff…

odata 搜索帮助

参考如下链接&#xff1a; FIORI ELement list report 细节开发&#xff0c;设置过滤器&#xff0c;搜索帮助object page跳转等_fiori element label 变量-CSDN博客 注&#xff1a;odata搜索帮助可以直接将值带出来&#xff0c;而不需要进行任何的重定义 搜索帮助metedata配置…

Docker基本命令VS Code远程连接

Docker基本命令 创建自己的docker容器&#xff1a;docker run --net host --name Container_name --gpus all --shm-size 1t -it -v Your_Path:Your_Dir mllm:mac /bin/bashdocker run&#xff1a;用于创建并启动一个新容器-name&#xff1a;为当前新建的容器命名-gpus&#x…

大疆上云api直播功能如何实现

概述 流媒体服务器作为直播画面的中转站,它接收推流端的相机画面,同时拉流端找它获取相机的画面。整个流程如下: 在流媒体服务器上创建流媒体应用(app),一个流媒体服务器上面可以创建多个流媒体应用约定推拉流的地址。假设流媒体服务器工作在1935端口上面,假设创建的流…

理解文字识别:一文读懂OCR商业化产品的算法逻辑

文字识别是一项“历久弥新”的技术。早在上世纪初&#xff0c;工程师们就开始尝试使用当时有限的硬件设备扫描并识别微缩胶片、纸张上的字符。随着时代和技术的发展&#xff0c;人们在日常生活中使用的电子设备不断更新换代&#xff0c;文字识别的需求成为一项必备的技术基础&a…

使用 Cursor、MCP 和 Figma 实现工程化项目自动化,提升高达 200% 效率

直接上手不多说其他的&#xff01; 一、准备动作 1、Cursor下载安卓 1.1访问官方网站 打开您的网络浏览器&#xff0c;访问 Cursor 的官方网站&#xff1a;https://www.cursor.com/cn 1.2开始下载: 点击"Download for free" 根据您的浏览器设置&#xff0c;会自…

Arduino、ESP32驱动GUVA-S12SD UV紫外线传感器(光照传感器篇)

目录 1、传感器特性 2、控制器和传感器连线图 3、驱动程序 UV紫外线传感器是一个测试紫外线总量的最佳传感器,它不需要使用波长滤波器,只对紫外线敏感。 Arduino UV紫外线传感器,直接输出对应紫外线指数(UV INDEX)的线性电压,输出电压范围大约0~1100mV(对应UV INDEX值…

PTA 1097-矩阵行平移

给定一个&#x1d45b;&#x1d45b;nn的整数矩阵。对任一给定的正整数&#x1d458;<&#x1d45b;k<n&#xff0c;我们将矩阵的奇数行的元素整体向右依次平移1、……、&#x1d458;、1、……、&#x1d458;、……1、……、k、1、……、k、……个位置&#xff0c;平移…

Notepad++ 替换 换行符 为 逗号

多行转一行&#xff0c;逗号分隔 SPO2025032575773 SPO2025032575772 SPO2025032575771 SPO2025032575771 SPO2025032575770为了方便快速替换&#xff0c;我们需要先知道这样类型的数据都存在哪些换行符。 点击【视图】-【显示符号】-【显示行尾符】 对于显示的行尾换行符【C…

使用飞书API自动化更新共享表格数据

飞书API开发之自动更新共享表格 天马行空需求需求拆解1、网站数据爬取2、飞书API调用2.1 开发流程2.2 创建应用2.3 配置应用2.4 发布应用2.5 修改表格权限2.6 获取tenant_access_token2.7 调用API插入数据 总结 天马行空 之前一直都是更新的爬虫逆向内容&#xff0c;工作中基本…

使用vscode搭建pywebview集成vue项目示例

文章目录 前言环境准备项目源码下载一、项目说明1 目录结构2 前端项目3 后端项目获取python安装包(选择对应版本及系统) 三、调试与生成可执行文件1 本地调试2 打包应用 四、核心代码说明1、package.json2、vite.config.ts设置3、main.py后端入口文件说明 参考文档 前言 本节我…