C++设计模式_09_Abstract Factory 抽象工厂
与上篇介绍的Factory Method工厂方法模式一样,Abstract Factory 抽象工厂模式也属于典型的“对象创建模式”模式,解决的问题也极其相似,在理解了Factory Method工厂方法模式的基础上再去理解Abstract Factory 抽象工厂模式就会变得更加容易。
文章目录
- 1. 动机(Motivation)
- 2. 代码演示Factory Method工厂方法模式
- 2.1 常规方法
- 2.2 Factory Method工厂方法
- 2.3 Abstract Factory 抽象工厂模式
- 3. 模式定义
- 4. 结构(Structure)
- 5. 要点总结
- 6. 其他参考
1. 动机(Motivation)
- 在软件系统中,经常面临着
“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。 - 如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合?
2. 代码演示Factory Method工厂方法模式
结合代码分析什么是“一系列相互依赖的对象”
2.1 常规方法
假如有一个任务需要写一个访问的是SQL Server的数据访问层,在数据访问层需要创建一系列对象,需要创建数据库的链接SqlConnection* connection,创建数据库的命令对象SqlCommand* command,创建数据库的DataReader对象SqlDataReader* reader,这些都是跟SQL Server相关的。
class EmployeeDAO{public:vector<EmployeeDO> GetEmployees(){SqlConnection* connection =new SqlConnection();connection->ConnectionString = "...";SqlCommand* command =new SqlCommand();command->CommandText="...";command->SetConnection(connection);SqlDataReader* reader = command->ExecuteReader();while (reader->Read()){}}
};
但是当客户的数据库发生变化,变为Oracle、MySQL、DB2等,对应的类型就需要变化,一旦使用new就会绑死在SQL Server上,这个类就不适用于多种数据库的变化,假设需要支持多种数据库,大家第一个反应就是需要做到面向接口的编程。
2.2 Factory Method工厂方法
在上面代码的基础进行修改,结合上篇介绍的引入Factory Method工厂方法来代替new,就得到使用Factory Method工厂方法模式解决问题的代码。
//数据库访问有关的基类接口
class IDBConnection{};
class IDBConnectionFactory{
public:virtual IDBConnection* CreateDBConnection()=0;
};class IDBCommand{};
class IDBCommandFactory{
public:virtual IDBCommand* CreateDBCommand()=0;
};class IDataReader{};
class IDataReaderFactory{
public:virtual IDataReader* CreateDataReader()=0;
};//支持SQL Server
class SqlConnection: public IDBConnection{};
class SqlConnectionFactory:public IDBConnectionFactory{};class SqlCommand: public IDBCommand{};
class SqlCommandFactory:public IDBCommandFactory{};class SqlDataReader: public IDataReader{};
class SqlDataReaderFactory:public IDataReaderFactory{};//支持Oracle
class OracleConnection: public IDBConnection{};class OracleCommand: public IDBCommand{};class OracleDataReader: public IDataReader{};class EmployeeDAO{IDBConnectionFactory* dbConnectionFactory;IDBCommandFactory* dbCommandFactory;IDataReaderFactory* dataReaderFactory;public:vector<EmployeeDO> GetEmployees(){IDBConnection* connection =dbConnectionFactory->CreateDBConnection();connection->ConnectionString("...");IDBCommand* command =dbCommandFactory->CreateDBCommand();command->CommandText("...");command->SetConnection(connection); //关联性,命令和链接时相关的对象IDBDataReader* reader = command->ExecuteReader(); //关联性while (reader->Read()){}}
};
上面的实现方法也已经解决了问题,但是暴露了什么问题
IDBConnectionFactory* dbConnectionFactory;中假如传入的是SqlConnectionFactory,但是IDBCommandFactory* dbCommandFactory;中是否可以传入OracleCommandFactory,显然是不可以的。这三个对象必须是同系列同组的,他们之间存在关联性,command和connection等之间是存在关联的。
这里就带来紊乱性,假如未来传入了不同的factory给你,出现传入SqlConnectionFactory、OracleCommandFactory、MySQLDataReaderFactory那就乱套了,无法搭配到一起,这就引出了Abstract Factory 抽象工厂模式。
2.3 Abstract Factory 抽象工厂模式
//数据库访问有关的基类
class IDBConnection{};class IDBCommand{};class IDataReader{};class IDBFactory{
public:virtual IDBConnection* CreateDBConnection()=0;virtual IDBCommand* CreateDBCommand()=0;virtual IDataReader* CreateDataReader()=0;};//支持SQL Server
class SqlConnection: public IDBConnection{};
class SqlCommand: public IDBCommand{};
class SqlDataReader: public IDataReader{};class SqlDBFactory:public IDBFactory{
public:virtual IDBConnection* CreateDBConnection()=0;virtual IDBCommand* CreateDBCommand()=0;virtual IDataReader* CreateDataReader()=0;};//支持Oracle
class OracleConnection: public IDBConnection{};class OracleCommand: public IDBCommand{};class OracleDataReader: public IDataReader{};class EmployeeDAO{IDBFactory* dbFactory;public:vector<EmployeeDO> GetEmployees(){IDBConnection* connection =dbFactory->CreateDBConnection();connection->ConnectionString("...");IDBCommand* command =dbFactory->CreateDBCommand();command->CommandText("...");command->SetConnection(connection); //关联性IDBDataReader* reader = command->ExecuteReader(); //关联性while (reader->Read()){}}
};
因为这3个factory特别有相关性,那用1个factory就可以了,将这3个类放在一起,实现高内聚松耦合。
大家看到这里就发现使用一个工厂,这就保证了关联性,解决了上面提到问题。从上面的代码可以看出Abstract Factory 其实被称为Family Factory更为合适,但是GOF/gaofour/4位大师已经定义了这样的名字,我们就不去计较这个名字了。
3. 模式定义
提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。
——《设计模式》GoF
“提供一个接口”的接口就是IDBFactory,创建了IDBConnection、IDBCommand、IDataReader等
4. 结构(Structure)

上图是《设计模式》GoF中定义的Abstract Factory 抽象工厂模式的设计结构。结合上面的代码看图中最重要的是看其中稳定和变化部分,也就是下图中红框、蓝框和绿框框选的部分。

5. 要点总结
- 如果没有应对“多系列对象构建”的需求变化,则没有必要使用Abstract Factory模式,这时候使用简单的工厂完全可以。
- “系列对象”指的是在某一特定系列下的对象之间有相互依赖、或作用的关系。不同系列的对象之间不能相互依赖。
- Abstract Factory模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。
第三点的意思是可以增加SQL、Oracle等系列,但是类内增加新对象就不可以了,因为SqlDBFactory是一个抽象基类,抽象基类要求稳定,这就是该模式的缺点,模式中稳定的部分就是缺点。
当所有地方都变化就没有模式可以解决,当所有地方都稳定
Abstract Factory 抽象工厂模式其实跟Factory Method工厂方法模式,很接近,也可以说Factory Method工厂方法模式是Abstract Factory 抽象工厂模式的特例。
当以下代码创建三个对象
class IDBFactory{
public:virtual IDBConnection* CreateDBConnection()=0;virtual IDBCommand* CreateDBCommand()=0;virtual IDataReader* CreateDataReader()=0;};
变为创建一个对象,就是Factory Method工厂方法模式
class IDBFactory{
public:virtual IDBConnection* CreateDBConnection()=0;};
有些地方直接将Abstract Factory 抽象工厂模式和Factory Method工厂方法模式直接称作工厂模式。
6. 其他参考
C++设计模式——抽象工厂模式
相关文章:
C++设计模式_09_Abstract Factory 抽象工厂
与上篇介绍的Factory Method工厂方法模式一样,Abstract Factory 抽象工厂模式也属于典型的“对象创建模式”模式,解决的问题也极其相似,在理解了Factory Method工厂方法模式的基础上再去理解Abstract Factory 抽象工厂模式就会变得更加容易。…...
一些前端面试思考
回流和重绘 先牢记这句话,回流必将引起重绘,而重绘不一定会引起回流。回流的代价要远大于重绘。 当你给一个元素更换颜色,这样的行为是不会影响页面布局的,DOM树不会变化,但颜色变了,渲染树得重新渲染页面&…...
Spring MVC(上)
1、Spring MVC简介: MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分 M:Model,模型层,指工程中的JavaBean,作用是处理数据 JavaBean分为两类: 一类称为实体类Bean:专…...
ORACLE内存结构
内存体系结构 目录 内存体系结构 2.1自动内存管理 2.2自动SGA内存管理 2.3手动SGA内存管理 2.3.1数据库缓冲区 2.3.1.1保留池 2.3.1.2回收池 2.3.2共享池 2.3.2.1SQL查询结果和函数查询结果 2.3.2.2库缓存 2.3.2.3数据字典缓存 2.3.3大池 2.3.4 …...
excel常用的几个函数
1、MID函数 通常用来返回返回指定字符串中的子串。 函数公式: MID(string, starting_at, extract_length) String(必填):包含要提取字符的文本字符串 starting_at(必填):文本中要提取的第一个字…...
【Bug】【内存相关】偶然发现一个内存溢出Bug复盘
一、问题 跑自动化用例的时候,uat-sg环境,发现SGW经常会返回 502 Bad Gateway响应 二、原因 经过SRE和BE Dev共同排查,502 是从ALB-- > 后端服务 后端服务无法响应导致,ALB会直接给客户端返回502。 服务端:由于c…...
python读写.pptx文件
1、读取PPT import pptx pptpptx.Presentation(rC:\Users\user\Documents\\2.pptx) # ppt.save(rC:\Users\user\Documents\\1.pptx) # slideppt.slides.add_slide(ppt.slide_layouts[1])# 读取所有幻灯片上的文字 for slide in ppt.slides:for shape in slide.shapes:if shape…...
【Godot】【BUG】4.x NavigationAgent 导航不生效
4.2.beta2 试了半天才发现原来默认只对第一个有导航的 TileMap 的第 1 层 生效,而我设置的导航层不是第一层,然后我新建了一个 TileMap 将导航的瓦片设置到这个 TileMap 上了,如图 这样就解决了问题,不用再修改默认设置的东西了&a…...
Rust逆向学习 (1)
文章目录 Hello, Rust Reverse0x01. main函数定位0x02. main函数分析line 1line 2line 3line 4~9 0x03. IDA反汇编0x04. 总结 近年来,Rust语言的热度越来越高,很多人都对Rust优雅的代码和优秀的安全性赞不绝口。对于开发是如此,对于CTF也是如…...
【Golang | reflect】利用反射实现方法的调用
引言 go语言中,如果某个数据类型实现了一系列的方法,如何批量去执行呢,这时候就可以利用反射里的func (v Value) Call(in []Value) []Value 方法。 // Call calls the function v with the input arguments in. // For example, if len(in)…...
Teleport
从官网中获取到的代码如下 App.vue <template><div class"outer"><h3>Tooltips with Vue 3 Teleport</h3><div><MyModal /></div></div> </template> <script setup> import MyModal from "./My…...
flutter与原生 相互通信实战
一、原生和flutter 通信 ios 通信类 CommonUtil.swift import Foundation import Flutterpublic class CommonUtil {public static func emitEvent(channel: FlutterMethodChannel, method: String, type: String, errCode: Int32?, errMsg: String?, data: Any?){safeMa…...
结构光相机原理
结构光相机原理...
ubuntu安装Anaconda
下载 Anaconda 进入 Ubuntu,自己新建下载路径,输入以下命令开始下载 注意,如果不是 x86_64,需要去镜像看对应的版本(https://mirrors.bfsu.edu.cn/anaconda/archive/?CM&OA) wget https://mirrors.…...
【RNA structures】RNA转录的重构和前沿测序技术
文章目录 RNA转录重建1 先简单介绍一下测序相关技术2 Map to Genome Methods2.1 Step1 Mapping reads to the genome2.2 Step2 Deal with spliced reads2.3 Step 3 Resolve individual transcripts and their expression levels 3 Align-de-novo approaches3.1 Step 1: Generat…...
4、Kafka 消费者
5.1 Kafka 消费方式 5.2 Kafka 消费者工作流程 5.2.1 消费者总体工作流程 5.2.2 消费者组原理 Consumer Group(CG):消费者组,由多个consumer组成。形成一个消费者组的条件,是所有消费者的groupid相同。 • 消费者组内…...
CSS3 渐变
CSS3 渐变可以让你在两个或多个指定的颜色之间显示平稳的过渡。 CSS3渐变有两种类型:线性渐变(Linear Gradients)和径向渐变(Radial Gradients)。 线性渐变(Linear Gradients): 线性…...
【Python 千题 —— 基础篇】分割有效信息
题目描述 题目描述 有时候我们需要截取字符串以获取有用的信息,比如对于字符串 “日期:2010-10-29”,我们需要截取后面的 10 个字符来获取日期,以便进行进一步分析。编写一个程序,输入一个字符串,然后输出…...
webrtc基于DTLS的端口复用技术
DTLS协议: DTLS(Datagram Transport Layer Security)数据包安全传输协议,用于在不可靠的数据包传输协议上(如UDP)提供数据的安全传输。 UDP多路复用: 一个UDP多路复用,被用来处理共享同一个UDP端口的多个并发的UDT连接。类似同一个tcp port上创建多个socket connec…...
【2024秋招】2023-9-20 度小满信贷系统平台部二面
1 面试官的部门介绍 我们部门是信贷系统平台部,主要是为度小满做一个服务,你应该也接触过信用卡,跟这种差不多,用户可以打进我们的系统申请一个额度,整个部门的规模大概是400-500人左右,我个人来自平台数据…...
从天气预报到视频预测:ConvLSTM实战项目入门(附PyTorch完整代码)
从天气预报到视频预测:ConvLSTM实战项目入门(附PyTorch完整代码) 当我们需要预测未来几小时的降雨量,或是推断视频下一帧的画面时,传统方法往往捉襟见肘。ConvLSTM的出现,为这类时空序列预测问题提供了全新…...
从“统计字符数”到“词频分析”:一个散列思想,搞定Python/Java/C++多语言实战
从“统计字符数”到“词频分析”:散列思想的多语言实战指南 在编程竞赛和实际开发中,频率统计是一个高频出现的经典问题。无论是统计文本中字符出现的次数,分析用户行为日志中的事件频率,还是计算电商平台上商品的购买热度&#x…...
2025届毕业生推荐的五大AI学术神器推荐榜单
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 对于那些想要降低文本AI检测率的用户来讲,专业的降AI率网站能给出高效的解决办法…...
3步永久备份QQ空间青春记忆:GetQzonehistory数据拯救方案
3步永久备份QQ空间青春记忆:GetQzonehistory数据拯救方案 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 在数字记忆快速迭代的时代,你是否曾担心那些承载青春印…...
从CTF杂项签到题到实战:手把手教你用ZipCenOp和010Editor破解伪加密与文件头修复
从CTF杂项签到题到实战:手把手教你用ZipCenOp和010Editor破解伪加密与文件头修复 在网络安全竞赛和实际渗透测试中,压缩包分析是数字取证的基础技能。本文将带你从零开始,掌握Zip伪加密识别、文件头修复等核心技巧,并通过实战案例…...
如何快速掌握ModTheSpire:杀戮尖塔模组加载器的终极配置指南
如何快速掌握ModTheSpire:杀戮尖塔模组加载器的终极配置指南 【免费下载链接】ModTheSpire External mod loader for Slay The Spire 项目地址: https://gitcode.com/gh_mirrors/mo/ModTheSpire 你是否厌倦了《杀戮尖塔》原版游戏内容?想要体验更…...
Docker沙箱配置实战手册(生产环境零事故配置模板)
第一章:Docker沙箱配置的核心价值与生产级定位Docker沙箱并非仅用于开发环境的临时隔离机制,而是现代云原生基础设施中保障服务可预测性、安全边界与部署一致性的关键执行层。在生产环境中,一个经过严谨配置的Docker沙箱,实质上构…...
免费开源在线PPT制作工具:浏览器中打造专业演示文稿的终极指南
免费开源在线PPT制作工具:浏览器中打造专业演示文稿的终极指南 【免费下载链接】PPTist PowerPoint-ist(/pauəpɔintist/), An online presentation application that replicates most of the commonly used features of MS PowerPoint, all…...
当经典运筹学遇上深度强化学习:我们离‘一键最优’的智能工厂还有多远?
深度强化学习重构制造业调度:从理论到落地的关键突破 走进任何一家现代化制造工厂,你都会看到数百台设备在同步运转,成千上万的零件在不同工序间流转。这种复杂场景下的生产调度,堪称工业界的"终极算法挑战"。传统运筹学…...
【卷卷观察】一边是44%新歌是AI唱的,一边是广告男主脖子扭到后背:AI内容失控的AB面
两条新闻,放在一起读,越读越有意思。欧洲那边:流媒体平台Deezer上周公布了一组数据,平台每日新增音乐里,44%是AI生成的。每天75000首AI歌曲入库。调查发现,97%的用户根本分辨不出哪首是AI唱的、哪首是真人在…...
