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

C++设计模式——抽象工厂模式

文章目录

    • 抽象工厂模式的主要组成部分
    • 抽象工厂模式的一个典型例子
    • 抽象工厂模式用于其他场景
    • 抽象工厂模式与其他设计模式结合使用

C++ 中的抽象工厂模式是一种创建型设计模式,它主要用于处理对象家族的创建,这些对象之间可能存在一定的关联关系或属于相同的产品族。抽象工厂模式的核心目标是提供一个接口,允许客户端通过此接口创建一系列相关或相互依赖的对象,而不必知道具体产生的对象的具体类。

抽象工厂模式的主要组成部分

  1. 抽象工厂(Abstract Factory):这是一个接口,声明了一组用于创建相关或依赖对象的方法,每个方法对应一种产品对象。

    class AbstractFactory {
    public:virtual ~AbstractFactory() {}virtual IProductA* createProductA() = 0; // 创建产品A的抽象方法virtual IProductB* createProductB() = 0; // 创建产品B的抽象方法// ... 可能还有其他产品方法
    };
    
  2. 具体工厂(Concrete Factory):这是抽象工厂接口的具体实现类,它负责创建一个产品族内的具体产品对象。

    class ConcreteFactory1 : public AbstractFactory {
    public:IProductA* createProductA() override { return new ConcreteProductA1(); }IProductB* createProductB() override { return new ConcreteProductB1(); }
    };class ConcreteFactory2 : public AbstractFactory {
    // ...
    };
    
  3. 产品接口(Product Interface):代表产品对象的抽象接口,定义了产品的公共方法。

    class IProductA {
    public:virtual ~IProductA() {}// 声明产品A的相关操作
    };class IProductB {
    public:virtual ~IProductB() {}// 声明产品B的相关操作
    };
    
  4. 具体产品(Concrete Product):实现了产品接口的具体产品类。

    class ConcreteProductA1 : public IProductA {
    // 实现产品A1的具体行为
    };class ConcreteProductB1 : public IProductB {
    // 实现产品B1的具体行为
    };// 同样会有 ConcreteProductA2, ConcreteProductB2 等...
    

使用抽象工厂模式的优势在于:

  • 隔离了具体的产品实现:客户端只需关心抽象工厂的接口,无需了解创建对象的具体细节。
  • 方便产品族的整体替换:如果想切换到同一产品族的不同实现,只需更改使用的具体工厂即可。
  • 确保产品一致性:通过抽象工厂创建的对象遵循一套一致的设计规则,适合那些必须一起工作的对象集合。

然而,抽象工厂模式也有其局限性,例如难以添加新的产品种类,因为它要求修改抽象工厂接口以及相应的具体工厂实现。此外,随着产品数量的增加,系统的复杂性也会提高。

抽象工厂模式的一个典型例子

在实际应用中,抽象工厂模式的一个典型例子是操作系统 GUI 库的创建。比如,我们有一个抽象工厂来创建按钮、文本框等各种 GUI 组件,而每个具体工厂(如 WindowsFactory 或 LinuxFactory)则负责创建相应操作系统下的具体 GUI 组件。

// 抽象工厂接口
class GUIFactory {
public:virtual ~GUIFactory() {}virtual Button* createButton() const = 0;virtual TextBox* createTextBox() const = 0;// 其他组件的创建方法...
};// 具体工厂
class WindowsFactory : public GUIFactory {
public:Button* createButton() const override { return new WindowsButton(); }TextBox* createTextBox() const override { return new WindowsTextBox(); }// ...
};class LinuxFactory : public GUIFactory {
public:Button* createButton() const override { return new LinuxButton(); }TextBox* createTextBox() const override { return new LinuxTextBox(); }// ...
};// 产品接口
class Button {
public:virtual ~Button() {}virtual void draw() const = 0;// ...
};class TextBox {
public:virtual ~TextBox() {}virtual void draw() const = 0;// ...
};// 具体产品
class WindowsButton : public Button {
public:void draw() const override { /*绘制Windows风格的按钮*/ }// ...
};class WindowsTextBox : public TextBox {
public:void draw() const override { /*绘制Windows风格的文本框*/ }// ...
};// Linux下对应的Button和TextBox实现...

在客户端代码中,我们可以根据需要选择合适的工厂来创建一整套风格一致的界面组件:

int main() {GUIFactory* factory;if (isWindowsPlatform()) {factory = new WindowsFactory();} else if (isLinuxPlatform()) {factory = new LinuxFactory();}Button* myButton = factory->createButton();TextBox* myTextBox = factory->createTextBox();// 使用创建出来的组件myButton->draw();myTextBox->draw();delete myButton;delete myTextBox;delete factory;return 0;
}

这样,无论操作系统环境如何变化,客户端代码都可以保持不变,体现了开闭原则——对扩展开放,对修改关闭。同时,由同一家工厂创建出来的组件具有内在的一致性,可以很好地协同工作。

抽象工厂模式用于其他场景

此外,抽象工厂模式还常用于其他场景,例如:

  • 数据库访问:抽象工厂可以定义创建不同数据库连接、执行SQL命令等操作的方法,而具体工厂可以是MySQLFactory、OracleFactory等,分别用来创建各自数据库系统的连接对象和查询命令对象。
// 抽象工厂
class DatabaseFactory {
public:virtual ~DatabaseFactory() {}virtual Connection* createConnection() const = 0;virtual Query* createQuery() const = 0;
};// 具体工厂
class MySQLFactory : public DatabaseFactory {
public:Connection* createConnection() const override { return new MySQLConnection(); }Query* createQuery() const override { return new MySQLQuery(); }
};class OracleFactory : public DatabaseFactory {
public:Connection* createConnection() const override { return new OracleConnection(); }Query* createQuery() const override { return new OracleQuery(); }
};// 产品接口
class Connection {
public:virtual ~Connection() {}virtual bool connect(const std::string& host, int port, const std::string& user, const std::string& password) = 0;// 其他连接相关方法...
};class Query {
public:virtual ~Query() {}virtual ResultSet* execute(const std::string& sql) = 0;// 其他查询相关方法...
};// 具体产品类...

通过这种设计模式,软件架构得以解耦,使得各个部分能够独立变化和发展,同时确保了系统内部组件间的兼容性和一致性。在复杂的应用场景中,抽象工厂模式尤其有助于模块化设计和维护。

抽象工厂模式与其他设计模式结合使用

在更高级别的软件体系结构设计中,抽象工厂模式还可以与其他设计模式结合使用,以构建更为灵活和可扩展的解决方案。例如:

  • 与策略模式结合:抽象工厂可以返回一组实现了某种策略接口的对象,这样客户可以根据需求选择不同的策略组合。例如,在图形渲染引擎中,抽象工厂可以创建不同的渲染策略(如光照策略、纹理策略),然后将它们组合起来形成特定的效果。

  • 与工厂方法模式结合:抽象工厂中的某些方法可以进一步采用工厂方法模式,即在具体工厂内定义创建单个产品的工厂方法,使得产品创建逻辑更加灵活且易于扩展。

  • 与装饰器模式配合:当产品家族中存在需要逐步增强或修改的组件时,可以在获取基础组件后,通过装饰器模式为其添加额外的功能或属性。

  • 与服务定位器模式搭配:在大型系统中,抽象工厂可以与服务定位器模式相结合,通过服务定位器查找并注入所需的抽象工厂实例,以便在运行时决定具体使用哪种工厂。

总的来说,抽象工厂模式是一个强大而实用的设计模式,它不仅帮助我们组织和管理相关联的产品族,而且在很大程度上增强了代码的可复用性和可扩展性。但在实际应用时需要注意权衡其带来的灵活性与增加的复杂性,尤其是在产品家族变动频繁或者产品种类较少的情况下,直接使用简单工厂或工厂方法模式可能更为合适。

python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)

50个开发必备的Python经典脚本(11-20)

50个开发必备的Python经典脚本(21-30)

50个开发必备的Python经典脚本(31-40)

50个开发必备的Python经典脚本(41-50)
————————————————

​最后我们放松一下眼睛
在这里插入图片描述

相关文章:

C++设计模式——抽象工厂模式

文章目录 抽象工厂模式的主要组成部分抽象工厂模式的一个典型例子抽象工厂模式用于其他场景抽象工厂模式与其他设计模式结合使用 C 中的抽象工厂模式是一种创建型设计模式,它主要用于处理对象家族的创建,这些对象之间可能存在一定的关联关系或属于相同的…...

Windows安装VNC连接工具并结合cpolar实现远程内网Ubuntu系统桌面

文章目录 前言1. ubuntu安装VNC2. 设置vnc开机启动3. windows 安装VNC viewer连接工具4. 内网穿透4.1 安装cpolar【支持使用一键脚本命令安装】4.2 创建隧道映射4.3 测试公网远程访问 5. 配置固定TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址5.3 测试…...

Vue3 Hooks函数使用及封装思想

一、什么是Hooks函数? 想象一下,你在做饭,有一些调料你经常会用到,比如盐、酱油和辣椒。每次做饭时,你都会从柜子里拿出这些调料。如果你每次用完都把它们随便放在厨房的某个角落,下次做饭时就可能找不到它…...

YOLOv8改进涨点,添加GSConv+Slim Neck,有效提升目标检测效果,代码改进(超详细)

目录 摘要 主要想法 GSConv GSConv代码实现 slim-neck slim-neck代码实现 yaml文件 完整代码分享 总结 摘要 目标检测是计算机视觉中重要的下游任务。对于车载边缘计算平台来说,巨大的模型很难达到实时检测的要求。而且,由大量深度可分离卷积层构…...

华为s5720s-28p-power-li-ac堆叠配置

叠物理约束: • 连线推荐示意图选用产品子系列中固定的一款设备做示例,与选择产品时指定型号的外观可能不同。示意图主要用于让用户了解相同子系列设备可以用作堆叠的端口的位置,以及使用不同的连线方式时如何连接设备上的端口。因此&#xf…...

c# aes加密解密私钥公钥通钥

using System.Security.Cryptography; using System.Text; namespace EncryptTest { internal class Program { static void Main(string[] args) { Console.WriteLine("Hello, World!"); string 密 EncryptAESBASE64("你…...

上拉电阻与下拉电阻、电容的作用

上拉电阻与下拉电阻 在单片机电路中,上拉电阻和下拉电阻都是常见的电路元件,它们在数字电路设计中扮演着重要的角色。它们的作用如下: 1. **上拉电阻**: - **作用**:当一个引脚没有外部信号时,上拉电阻…...

《Spring Security 简易速速上手小册》第1章 Spring Security 概述(2024 最新版)

文章目录 1.1 Spring Security 的重要性1.1.1 基础知识详解1.1.2 主要案例:用户认证与授权1.1.3 拓展案例 1:OAuth2 社交登录1.1.4 拓展案例 2:JWT 认证 1.2 Spring Security 的核心特性1.2.1 基础知识详解1.2.2 主要案例:基于角色…...

vue页面菜单权限问题解决

带锚点的url,#后面部分后端获取不到. vue的页面是带有#的路由,#后端服务获取不到,只在浏览器端有用. URL 中的哈希符号 (#) 被用来作为网页中的 锚点 使用,锚点的含义就是页面中的某个特定的位置,这个位置可以被快速找到,很类似于在该位置抛…...

C++面试宝典第33题:数组组成最大数

题目 给定一组非负整数nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。 示例1: 输入:nums = [10, 2] 输出:"210" 示例2: 输入:nums = [3, 30, 34, 5, 9] 输出:"…...

“影像承载初心” 国际数字影像产业园2024首届摄影沙龙诚邀您的参与!

2024年2月29日,树莓集团总部国际数字影像产业园将举行“影像承载初心”2024首届摄影沙龙,活动现场邀请摄影业内大咖与专家共聚成都文创产业园,探讨摄影艺术及影像未来。诚邀您的参与! 国际数字影像产业园介绍: 国际数…...

【C语言】while循环语句

🎈个人主页:豌豆射手^ 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:C语言 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步&…...

2024数字中国创新大赛·数据要素赛道“能源大数据应用赛”正式上线!参赛指南请查收

近日,由国网福建电力承办的2024数字中国创新大赛能源大数据应用赛正式上线发布。赛事按照数字中国建设、能源革命的战略要求,围绕能源数据要素x、能源数字技术、能源商业模式等热点设置赛题,诚邀社会各界为加快建成新型电力系统出谋划策&…...

react-JSX基本使用

1.目标 能够知道什么是JSX 能够使用JSX创建React元素 能够在JSX中使用JS表达式 能够使用JSX的条件渲染和列表渲染 能够给JSX添加样式 2.目录 JSX的基本使用 JSX中使用JS表达式 JSX的条件渲染 JSX的列表渲染 JSX的样式处理 3.JSX的基本使用 3.1 createElement()的问题 A. …...

学习阶段单片机买esp32还是stm32?

学习阶段单片机买esp32还是stm32? 在开始前我有一些资料,是我根据网友给的问题精心整理了一份「stm32的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!&#xf…...

【Simulink系列】——Simulink子系统子系统封装模块库技术

声明:本系列博客参考有关专业书籍,截图均为自己实操,仅供交流学习! 引入 前面对于简单的动态系统仿真,可以直接建立模型,然后仿真。但是对于复杂的系统,直接建立系统会显得杂乱无章&#xff0…...

一加手机线刷2024版,param预载失败/MSM刷机工具报错

如果之前有刷第三方或者手机出问题,先去下载9008线刷包,可以去去大侠阿木的网站搜索。 这次的主题是param刷机报错,当你确保端口提示有QCOM端口,没有感叹号你需要先卸载设备及其驱动,重新插上手机,在WINDO…...

文件拖放到窗体事件

网上的实现1 实现结果 具体实现代码:注意需要使能允许拖拽 public partial class Form1 : Form {public Form1(){InitializeComponent();this.AllowDrop true; //允许拖拽}private void Form1_DragEnter(object sender, DragEventArgs e){this.Text DateTime.No…...

JAVA集成微信支付V3版JSAPI下单

一、引入微信支付SDK <dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-pay</artifactId> </dependency> 二、支付参数封装 Data ConfigurationProperties(prefix "wx.pay") public class WxP…...

opengles 背面剔除介绍(十二)

文章目录 前言一、OpenGL ES 剔除功能简介二、Opengl ES 剔除功能相关的API1.使能剔除功能2. 配置面剔除模式3. 设置剔除面的顺序4. 禁用剔除功能总结参考资料前言 本文主要介绍 opengles3.0 中的背面剔除相关知识,对于绘制3d 图形, 经常会用到它,并且它能提升渲染效率 软硬…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

Caliper 负载(Workload)详细解析

Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...

WPF八大法则:告别模态窗口卡顿

⚙️ 核心问题&#xff1a;阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程&#xff0c;导致后续逻辑无法执行&#xff1a; var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题&#xff1a…...