C++设计模式——抽象工厂模式
文章目录
- 抽象工厂模式的主要组成部分
- 抽象工厂模式的一个典型例子
- 抽象工厂模式用于其他场景
- 抽象工厂模式与其他设计模式结合使用
C++ 中的抽象工厂模式是一种创建型设计模式,它主要用于处理对象家族的创建,这些对象之间可能存在一定的关联关系或属于相同的产品族。抽象工厂模式的核心目标是提供一个接口,允许客户端通过此接口创建一系列相关或相互依赖的对象,而不必知道具体产生的对象的具体类。
抽象工厂模式的主要组成部分
-
抽象工厂(Abstract Factory):这是一个接口,声明了一组用于创建相关或依赖对象的方法,每个方法对应一种产品对象。
class AbstractFactory { public:virtual ~AbstractFactory() {}virtual IProductA* createProductA() = 0; // 创建产品A的抽象方法virtual IProductB* createProductB() = 0; // 创建产品B的抽象方法// ... 可能还有其他产品方法 }; -
具体工厂(Concrete Factory):这是抽象工厂接口的具体实现类,它负责创建一个产品族内的具体产品对象。
class ConcreteFactory1 : public AbstractFactory { public:IProductA* createProductA() override { return new ConcreteProductA1(); }IProductB* createProductB() override { return new ConcreteProductB1(); } };class ConcreteFactory2 : public AbstractFactory { // ... }; -
产品接口(Product Interface):代表产品对象的抽象接口,定义了产品的公共方法。
class IProductA { public:virtual ~IProductA() {}// 声明产品A的相关操作 };class IProductB { public:virtual ~IProductB() {}// 声明产品B的相关操作 }; -
具体产品(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堆叠配置
叠物理约束: • 连线推荐示意图选用产品子系列中固定的一款设备做示例,与选择产品时指定型号的外观可能不同。示意图主要用于让用户了解相同子系列设备可以用作堆叠的端口的位置,以及使用不同的连线方式时如何连接设备上的端口。因此…...
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”,全部无偿共享给大家!!…...
【Simulink系列】——Simulink子系统子系统封装模块库技术
声明:本系列博客参考有关专业书籍,截图均为自己实操,仅供交流学习! 引入 前面对于简单的动态系统仿真,可以直接建立模型,然后仿真。但是对于复杂的系统,直接建立系统会显得杂乱无章࿰…...
一加手机线刷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 图形, 经常会用到它,并且它能提升渲染效率 软硬…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)
一、OpenBCI_GUI 项目概述 (一)项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台,其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言,首次接触 OpenBCI 设备时,往…...
QT开发技术【ffmpeg + QAudioOutput】音乐播放器
一、 介绍 使用ffmpeg 4.2.2 在数字化浪潮席卷全球的当下,音视频内容犹如璀璨繁星,点亮了人们的生活与工作。从短视频平台上令人捧腹的搞笑视频,到在线课堂中知识渊博的专家授课,再到影视平台上扣人心弦的高清大片,音…...
