C++设计模式 #8 抽象工厂(Abstract Factory)

抽象工厂这个名字比较难以帮助理解,可以把抽象工厂理解为“品牌工厂”或者“家族工厂”。

动机

  • 在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。
  • 如何应对这种变化?如何绕过常规的创建方法(new),提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合?

举个栗子

我们有一个控制数据库连接和操作的类

class EmployeeDAO{public:vector<EmployeeDAO> GetEmployees(){SqlConnection* connection = new SqlConnection();connection->ConnectionString("...");SqlCommand* command = new SqlCommand();command->CommandText("...");command->SetConnection(connection);SqlDataReader* reader = command->ExecuteReader();while(reader->Read()){}}
};

我们使用这个类来连接一个数据库,并使用一些SQL语句来对数据库进行操作。然后使用reader来读取SQL语句得到的数据。

由于可以使用的数据库种类很多,比如针对oracle的数据库,我们可能需要另外再一个类来实现不同的实际操作。

在学习了工厂方法之后,我们可以根据工厂模式将SqlConnection,SqlCommand,SqlDataReader改写成以下模式。

class IDBconnection {
public:virtual void ConnectionString(string) = 0;
};
class SqlConnection : public IDBconnection {
public:virtual void ConnectionString(string s) {//do connection}
};
class OracleConnection : public IDBconnection {
public:virtual void ConnectionString(string s) {//do connection}
};class IDBconnectionFactory {
public:virtual IDBconnection* create() = 0;
};
class SqlConnectionFactory : public IDBconnectionFactory {IDBconnection* create() {return new SqlConnection();}
};
class OracleConnectionFactory : public IDBconnectionFactory {IDBconnection* create() {return new OracleConnection();}
};class ISqlCommand {
public:virtual void CommandText(string) = 0;virtual void SetConnection(IDBconnection*) = 0;virtual IDataReader* ExecuteReader() = 0;
};
class SqlCommand : public ISqlCommand {
public:virtual void CommandText(string) {//...}virtual void SetConnection(IDBconnection*) {//...}virtual IDataReader* ExecuteReader() {return new SqlDataReader();}
};
class OracleCommand : public ISqlCommand {
public:virtual void CommandText(string) {//...}virtual void SetConnection(IDBconnection*) {//...}virtual IDataReader* ExecuteReader() {return new OracleDataReader();}
};class ISqlCommandFactory {
public:virtual ISqlCommand* create() = 0;
};
class SqlCommandFactory : public ISqlCommandFactory {ISqlCommand* create() {return new SqlCommand();}
};
class OracleCommandFactory : public ISqlCommandFactory {ISqlCommand* create() {return new OracleCommand();}
};class IDataReader {
public:virtual bool Read() = 0;
};
class SqlDataReader : public IDataReader {
public:virtual bool Read() {//...return true;}
};
class OracleDataReader : public IDataReader {
public:virtual bool Read() {//...return true;}
};class EmployeeDAO {
private:IDBconnection* connection;ISqlCommand* command;IDataReader* reader;public:vector<EmployeeDAO> GetEmployees(IDBconnectionFactory* connectionFactory, ISqlCommandFactory* commanFactory) {connection = connectionFactory->create();connection->ConnectionString("...");command = commanFactory->create();command->CommandText("...");command->SetConnection(connection);reader = command->ExecuteReader();while (reader->Read()) {}}
};

我们使用工厂模式在运行时创建EmployeeDAO的connection和command指针。

问题

我们使用单纯的工厂模式来创建不同的connection和command的子类来操作不同的数据库。这表面上看起来已经解决了这个问题。

但是,假如出现了这种情况,在调用GetEmployees时,我们传入的参数是,

GetEmployees(SqlConnectionFactory, OracleCommandFactory)

这样的代码当然可以通过编译,但是我们用Oracle数据库的命令其他的数据库,当然会导致一系列的错误。

重构

class IDBFactory {
public:virtual IDBconnection* create_connection() = 0;virtual ISqlCommand* create_command() = 0;
};class SqlFactory : public IDBFactory {
public:virtual IDBconnection* create_connection() {return new SqlConnection();}virtual ISqlCommand* create_command() {return new SqlCommand();}
};class OracleFactory : public IDBFactory {
public:virtual IDBconnection* create_connection() {return new OracleConnection();}virtual ISqlCommand* create_command() {return new OracleCommand();}
};class EmployeeDAO {
private:IDBconnection* connection;ISqlCommand* command;IDataReader* reader;public:vector<EmployeeDAO> GetEmployees(IDBFactory* factory) {connection = factory->create_connection();connection->ConnectionString("...");command = factory->create_command();command->CommandText("...");command->SetConnection(connection);reader = command->ExecuteReader();while (reader->Read()) {}}
};

将两个connection和command工厂合并,让它只能生产“同一种类的产品”。这样,我们既降低了耦合,又避免“产品种类”不同导致不能使用的情况。

结构

红色是稳定的,蓝色代表了一种变化,绿色代表了另一种变化。

可以对照上面的代码自己寻找一下图中的类和代码中的类的对应关系。

9.抽象工厂_哔哩哔哩_bilibili这里面,将ConreteFactory1,2其实是按sql和oracle分开的。视频中出现了一点小错误。

总结

  • 如果没有应对“多系列对象构建”的需求变化,则没有必要使用抽象工厂模式,这时候简单的工厂模式完全可以。
  • “系列对象”指在某一特定系列下的对象之间有相互依赖、或作用的关系。(不同数据库间的操作模块不能互相作用和依赖)
  • 抽象工厂模式主要应对“新系列”的需求变动。缺点在于难以应对“新对象”的需求变动。

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

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

相关文章

C# 常用数据类型及取值范围

1.常见数据类型和取值范围 序号数据类型占字节数取值范围1byte10 到 2552sbyte1-128 到 1273short 2-32,768 到 32,7674ushort20 到 65,5355int4-2,147,483,648 到 2,147,483,6476uint40 到 4,294,967,2957float41.5 x 10−45 至 3.4 x 10388double85.0 10−324 到 1.…

位运算|比特位计数、汉明距离

位运算|比特位计数、汉明距离 338 比特位计数 /** 比特位计数法一&#xff1a;Brian Kernighan 算法的原理是&#xff1a;对于任意整数 x&#xff0c;令 xx & (x−1)&#xff0c;该运算将 x 的二进制表示的最后一个 1 变成 0。因此&#xff0c;对 x 重复该操作&#xff0…

极智开发 | 解读英伟达软件生态 深度神经网络库cuDNN

欢迎关注,获取我的更多经验分享 大家好,我是极智视界,本文来介绍一下 解读英伟达软件生态 深度神经网络库cuDNN。 邀您加入我的知识星球「极智视界」,星球内有超多好玩的项目实战源码下载,链接:https://t.zsxq.com/0aiNxERDq cuDNN,全称为 NVIDIA CUDA Deep Neural Net…

Transform环境搭建与代码调试——Attention Is All Y ou Need

1、源代码 2、环境搭建 conda create -n transform python3.8 -y conda activate transform cd /media/lhy/Transforms/annotatedtransformerpip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple # # Uncomment for colabpip install -q torchdata…

一篇文章带你轻松入门Python

Python基础 1. Hello World! Python命令行 假设你已经安装好了Python, 那么在命令提示符输入: python 将直接进入python。然后在命令行提示符>>>后面输入: >>>print(Hello World!) 可以看到&#xff0c;随后在屏幕上输出: print是一个常用函数&#xf…

阿里云PolarDB数据库费用价格表

阿里云数据库PolarDB租用价格表&#xff0c;云数据库PolarDB MySQL版2核4GB&#xff08;通用&#xff09;、2个节点、60 GB存储空间55元5天&#xff0c;云数据库 PolarDB 分布式版标准版2核16G&#xff08;通用&#xff09;57.6元3天&#xff0c;阿里云百科aliyunbaike.com分享…

HPM6750开发笔记《开发环境的搭建》

目录 一&#xff0c;下载完整的HPM—SDK 二&#xff0c;安装硬件驱动 二&#xff0c;软件激活 三&#xff0c;创建工程 1.用文档中给的方法创建工程&#xff1a; 2.用sdk_env_v1.3.0中提供的工具创建工程&#xff1a; 一&#xff0c;下载完整的HPM—SDK 下载网址&#x…

Python sanic框架钉钉和第三方打卡机实现

同样还是需要开通钉钉应用这里就不错多说了 第一步:梳理逻辑流程 前提&#xff1a;打卡的机器是使用postgres数据库&#xff0c;由于因为某些原因&#xff0c;钉钉userId 我已经提前获取到了存放到数据库里。 1.用户打卡成功后&#xff0c;我们应该监听数据库进行查询&#xf…

SuperMap iClient3D for WebGL实现浮动点效果

文章目录 前言一、update方法二、创建实体点三、效果 前言 基于SuperMap iClient3D for WebGL实现浮动点效果&#xff0c;原理就是不断改变实体的高度&#xff0c;这里我们选择使用CallbackProperty来实现。 一、update方法 var cc 0 var dd truevar update function() {i…

单文件超过4GB就无法拷贝到U盘?这个你一定要知道

前言 随着现在科技发展&#xff0c;小伙伴们所使用的数据也越变越大。还记得WindowsXP流行的时候&#xff0c;XP的镜像文件仅为几百MB大小。 但是现在随便一个系统就有可能超过4GB。 如果单个文件超过4GB就有可能没办法拷贝进U盘&#xff0c;在这里就需要给小伙伴们普及一下U…

python学习14

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

浅谈IDC数据中心机房低压配电系统的组成与设计

随着我国移动互联网技术的不断发展&#xff0c;海量的数据资源日益庞大&#xff0c;IDC数据中心存储着这些大量的数据信息&#xff0c;其蕴含着巨大的研究和商业价值&#xff0c;因此数据中心IT设备的运行应具有较高的可靠性和稳定性。数据中心供配电系统是为机房内所有需要动力…

关于MySQL、分布式系统、SpringCloud面试题

前言 之前为了准备面试&#xff0c;收集整理了一些面试题。 本篇文章更新时间2023年12月27日。 最新的内容可以看我的原文&#xff1a;https://www.yuque.com/wfzx/ninzck/cbf0cxkrr6s1kniv MySQL 索引 说一下有哪些锁&#xff1f; 行锁有哪些&#xff1f; 性能优化 分库分表…

drf知识-08

Django之了解DRF框架 # 介绍&#xff1a;DRF全称 django rest framework # 背景&#xff1a; 在序列化与反序列化时&#xff0c;虽然操作的数据不尽相同&#xff0c;但是执行的过程却是相似的&#xff0c;也就是说这部分代码是可以复用简化编写的 增&#xff1a;校验请…

【《设计模式之美》】如何取舍继承与组合

文章目录 什么情况下不推荐使用继承&#xff1f;组合相比继承有哪些优势&#xff1f;使用组合、继承的时机 本文主要想了解&#xff1a; 为什么组合优于继承&#xff0c;多用组合少用继承。如何使用组合来替代继承哪些情况适用继承、组合。有哪些设计模式使用到了继承、组合。 …

打地鼠游戏来了

主要利用js鼠标点击事件和window.setInterval&#xff08;&#xff09;回调函数来进行实现的. 源码获取方式&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1eW9qvX3zFH9qlH82-I4yOA 提取码&#xff1a;1233

信息安全概论快速复习(期末急救)

文章目录 1、DES中的S-盒输入输出问题 &#xff08;不需要记住S-盒&#xff09;2、Kerberos认证系统3、简答题&#xff08;三题每题8分&#xff09;&#xff1a;课后习题第一章、第三章、第四章第一章&#xff1a;重点关注安全模型内容&#xff0c;有几种&#xff0c;有几个分级…

活动回顾 (下) | 机器学习系统趋势研判,大咖金句汇总

作者&#xff1a;三羊、李宝珠、李玮栋、Yudi、xixi 编辑&#xff1a;李宝珠 在大模型时代的浪潮中&#xff0c;机器学习系统正经历着前所未有的变革。模型规模的急剧膨胀&#xff0c;让我们见证了 AI 能力的巨大提升&#xff0c;然而这种提升不仅为各个领域带来了新的机遇&…

音视频的编码格式与封装格式

音视频的编码格式与封装格式是两个不同的概念&#xff0c;视频封装格式常见的有&#xff1a;mp4&#xff0c;rmvb&#xff0c;avi&#xff0c;mkv&#xff0c;mov&#xff0c;mpg&#xff0c;vob&#xff0c;3gp&#xff0c;asf&#xff0c;rmvb&#xff0c;wmv&#xff0c;div…

关于设计模式、Java基础面试题

前言 之前为了准备面试&#xff0c;收集整理了一些面试题。 本篇文章更新时间2023年12月27日。 最新的内容可以看我的原文&#xff1a;https://www.yuque.com/wfzx/ninzck/cbf0cxkrr6s1kniv 设计模式 单例共有几种写法&#xff1f; 细分起来就有9种&#xff1a;懒汉&#x…