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

设计模式之抽象工厂模式

前言

工厂模式一般指的是简单工厂模式、工厂方法模式、抽象工厂模式,这是三种工厂模式的最后一篇,其他两种的文章链接如下:

设计模式之简单工厂模式-CSDN博客

设计模式之工厂方法模式-CSDN博客

建议三种模式放在一起对比学习,更能领会其中的奥秘。看懂UML类图,更是奥秘中的奥秘哦,在UML类图中不同的箭头和线条,代表的意义是不同的,发现有很多人都画错了,这里简单的梳理了一下,如果需要可以移步这里:设计模式之基础:UML类图怎么看?_uml图怎么看-CSDN博客

什么是抽象工厂模式?

抽象工厂模式是一种创建型的工厂模式,它提供了一个接口,使客户端可以在不指定具体产品的情况下创建多个产品组中的产品对象。当存在多个抽象角色时,抽象工厂模式可以用来创建一个工厂,该工厂能够根据需要生成相应类型的产品。这种模式将产品的生成和使用解耦,使得客户端无需了解具体产品的实现细节。

抽象工厂模式的核心思想是将工厂封装成了一个抽象接口,通过这个接口来创建产品。它允许客户端通过调用抽象工厂的接口来生成多个产品族中的产品对象,而无需知道每个产品族的实现细节。抽象工厂模式适用于存在多个产品族的情况,这些产品族具有不同的实现,但是客户端需要使用多个产品族中的产品。通过使用抽象工厂模式,客户端可以灵活地使用不同的产品族,而无需对代码进行大量修改。

与工厂方法模式有什么区别?

抽象工厂模式和工厂方法模式都是设计模式中的对象创建型模式,主要用于封装对象的创建过程,以减少代码耦合。两种模式之间存在以下区别:

  1. 工厂角色不同:在工厂方法模式中,工厂方法是实现客户端与具体产品类解耦的关键,客户端通过继承或实现工厂方法实现创建产品的功能。而在抽象工厂模式中,抽象工厂是客户端与具体产品类解耦的关键,客户端通过实例化抽象工厂对象并调用其创建产品的方法实现创建产品的功能。
  2. 创建产品的模式不同:工厂方法模式中,每个具体工厂类只能创建一个具体产品类的实例,即“一对一”的关系。而在抽象工厂模式中,每个具体工厂类可以创建多个具体产品类的实例,即“一对多”的关系。
  3. 产品类型不同:在工厂方法模式中,工厂方法返回的产品类型是固定的,即每个具体工厂类只能创建一个固定类型的产品。而在抽象工厂模式中,抽象工厂返回的产品类型可以是多种多样的,即每个具体工厂类可以创建多个不同类型的产品。

总之,抽象工厂模式相对于工厂方法模式,更适用于创建一系列相关或相互依赖的对象,以及对产品进行分类和组织的情况。

抽象工厂UML类图

在抽象工厂模式中,存在四种角色:

  1. 抽象工厂角色(Abstract Factory):担任这个角色的是工厂方法模式的核心,它是与应用系统业务逻辑无关的。抽象工厂包含对多个产品结构的声明,任何工厂类都必须实现这个接口。
  2. 具体工厂角色(Concrete Factory):这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的业务逻辑紧密相关的。具体工厂类是抽象工厂的一个实现,负责实例化某个产品族中的产品对象。
  3. 抽象产品角色(Abstract Product):担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。抽象模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
  4. 具体产品角色(Concrete Product):抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。

抽象工厂实现示例

还以女娲造人的传说举一个例子:刚开始造人,女娲觉得还挺有意思的,造的时间长了,都是黄皮肤的中国人,显得很单调,没啥意思了,于是拓展了一下业务,开始造黑色皮肤的非洲人了,用抽象工厂模式来演示这个过程会是什么样呢?

UML类图如下:

伪代码示例如下:

public interface Human {/*** 人类会吃东西*/void eat();/*** 人类会喝东西*/void drink();
}
public class YellowMan implements Human {@Overridepublic void eat() {System.out.println("黄色皮肤的中国男人在吃东西");}@Overridepublic void drink() {System.out.println("黄色皮肤的中国男人在喝水");}
}
public class YelloWoman implements Human {@Overridepublic void eat() {System.out.println("黄色皮肤的中国女人在吃东西");}@Overridepublic void drink() {System.out.println("黄色皮肤的中国女人在喝水");}
}
public interface HumanFactory {Human createMan();Human createWoman();
}
public class YelloHumanFactory implements HumanFactory{@Overridepublic Human createMan() {return new YellowMan();}@Overridepublic Human createWoman() {return new YelloWoman();}
}
public class BlackHumanFactory implements HumanFactory{@Overridepublic Human createMan() {return new BlackMan();}@Overridepublic Human createWoman() {return new BlackWoman();}
}
public class Test {public static void main(String[] args) {HumanFactory yellowHumanFactory=new YelloHumanFactory();Human man = yellowHumanFactory.createMan();Human woman = yellowHumanFactory.createWoman();man.eat();man.drink();woman.eat();woman.drink();HumanFactory blackHumanFactory=new BlackHumanFactory();Human man1 = blackHumanFactory.createMan();Human woman1 = blackHumanFactory.createWoman();man1.eat();man1.drink();woman1.eat();woman1.drink();}
}

女娲这都造人业务都拓展到海外了,光能造黄种人、黑种人怎么行,还想造白种人怎么办呢?很简单:

1、实现Human接口,再实现一个白种男人、一个白种女人的类;

2、实现HumanFactory接口,再实现一个白种人的制造工厂;

public class WhiteMan implements Human {@Overridepublic void eat() {System.out.println("白种欧洲男人吃东西");}@Overridepublic void drink() {System.out.println("白种欧洲男人在喝水");}
}
public class WhiteWoman implements Human {@Overridepublic void eat() {System.out.println("白种欧洲女人在吃东西");}@Overridepublic void drink() {System.out.println("白种欧洲女人在喝水");}
}
public class WhiteHumanFactory implements HumanFactory{@Overridepublic Human createMan() {return new WhiteMan();}@Overridepublic Human createWoman() {return new WhiteWoman();}
}
public class Test {public static void main(String[] args) {HumanFactory whiteHumanFactory=new WhiteHumanFactory();Human man2 = whiteHumanFactory.createMan();Human woman2 = whiteHumanFactory.createWoman();man2.eat();man2.drink();woman2.eat();woman2.drink();}
}

有一天女娲觉得光造些男人、女人太单调了,男人、女人之间老是干架,怎么调合一下呢?那就造一些可爱小朋友吧。这时就会发现,如果还使用抽象工厂模式,就会很尴尬:HumanFactory接口里只有造男人、造女人的抽象方法,如果再加一个造小朋友的接口,就要对HuanFactory接口及其实现类具体工厂修改,这就破坏了开闭原则。如果除了造黑人、白人、黄人外,还想造点绿巨人,其实倒还好,和增加造白人的逻辑一样。这就是在决定是否使用抽象工厂模式的秘密所在,如果要扩展的是一个产品族,比较简单且适用,如果想丰富某一产品族的某个产品系列,就比较麻烦了;

抽象工厂应用场景

有没有发现这种方式非常好?完全符合开闭原则,无须对原有系统进行修改;下面就总结一下抽象工厂模式的实际应用场景有哪些?

  1. 产品组装:在现实生活中,抽象工厂模式最典型的例子就是产品的组装。例如,在电脑的组装过程中,我们通常需要选择一系列的配件,如CPU、硬盘、内存、主板、电源、机箱等。选择不同的配件,组装出来的电脑是不同的,这就可以看作是在使用不同的工厂来生产不同的产品。
  2. 提供产品类库:如果我们需要提供一个产品类库,但只想显示它们的接口而不是实现,那么就可以使用抽象工厂模式。例如,在设计一个绘图软件时,我们可能希望提供一个图形类库,但并不想暴露出每个图形的具体实现细节,这时就可以使用抽象工厂模式来生成各种图形对象。
  3. 多产品系列:如果一个系统需要由多个产品系列中的一个来配置,那么也可以使用抽象工厂模式。例如,在汽车制造中,可能需要根据用户的选择来配置不同的汽车模型。
  4. 独立于产品的创建、组合和表示:如果一个系统需要独立于它的产品的创建、组合和表示,那么也可以使用抽象工厂模式。例如,在开发一个游戏引擎时,我们可能希望游戏开发者能够使用我们提供的引擎来创建各种类型的游戏,而无需关心游戏引擎底层的具体实现。

总结

抽象工厂模式是一种设计程序时的工程方法,前面也说过,方法是为了解决问题的,不是灵丹妙药,用上了就一定很好,是绝不能生搬硬套的,重在理解和灵活运用。

对于抽象工厂模式有以下优点:

  1. 隔离了具体类的生成,使得客户端并不需要知道什么被创建。
  2. 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
  3. 增加新的产品族很方便,无须修改已有系统,符合开闭原则。

抽象工厂模式也有一些缺点:

  1. 增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,违背了开闭原则。
  2. 如果客户端需要创建多个产品族的多个对象,那么代码会变得很冗长和复杂。
  3. 如果产品族之间有依赖关系,那么需要仔细考虑如何处理这些依赖关系,以避免出现循环依赖或其他问题。

因此,在使用抽象工厂模式时,需要根据具体的情况来考虑其优缺点,并决定是否使用该模式。

相关文章:

设计模式之抽象工厂模式

前言 工厂模式一般指的是简单工厂模式、工厂方法模式、抽象工厂模式,这是三种工厂模式的最后一篇,其他两种的文章链接如下: 设计模式之简单工厂模式-CSDN博客 设计模式之工厂方法模式-CSDN博客 建议三种模式放在一起对比学习,…...

Compose预处理组件大比拼:性能、应用场景和可视化对比总结

在机器学习的世界里,预处理组件就像是厨师的烹饪工具。选择合适的工具不仅可以让整个烹饪过程更加顺畅,还能确保最终的菜肴更加美味。 本文将深入探讨四种“烹饪工具”:TransformedTargetRegressor、make_column_transformer、make_column_selector和ColumnTransformer。通…...

【小米】Linux 实习生

下午不准备去图书馆自习来着,中午就狠狠地多睡了一个小时,三点起床靠在椅子上剥柚子,太爽了,这秋天的下午。“邮件:小米公司邀请你预约面试时间”.......... 我擦,投了一个月了,认真准备的时候…...

python一点通:coroutine (协程)是什么和重要知识点?

协程已经成为Python用于编写并发和异步代码的重要工具之一。在这篇博客文章中,我们将深入探讨协程是什么,它们的优点,以及它们与传统的线程和进程有何不同。 什么是协程? 协程是用于合作式多任务处理的子程序(或函数…...

QCC51XX-QCC30XX系列开发教程(实战篇) 之 12.1-空间音频相关模块的概述

查看全部教程开发请点击:全网最全-QCC51xx-QCC30xx(TWS)系列从入门到精通开发教程汇总(持续更新中) ==================================================================== 版权归作者所有,未经允许,请勿转载。 ==========================================...

Servlet的生命周期

2023.10.18 WEB容器创建的Servlet对象,这些Servlet对象都会被放到一个集合当中(HashMap),这个集合当中存储了Servlet对象和请求路径之间的关系 。只有放到这个HashMap集合中的Servlet才能够被WEB容器管理,自己new的Ser…...

2.4 如何在FlinkSQL使用DataGen(数据生成器)

1、DataGen SQL 连接器 FLinkSQL中可以使用内置的DataGen SQL 连接器来生成测试数据 官网链接:DataGen SQL 连接器 2、随机数数据生成器 随机数数据生成器支持随机生成 char、varchar、binary、varbinary、string 类型的数据 它是一个无界流的数据生成器 -- TO…...

Gin + Ant Design Pro JWT认证

文章目录 一:介绍二:Gin JWT 后台1. Claims 定义2. 创建和解析Token3. Gin中间件编写4. 辅助函数 三:Ant Design Pro JWT认证四:Gin中间件和使用示范 一:介绍 JWT现在比较流行的认证方式,微服务中使用特别…...

canvas实现图片标注,绘制区域

使用canvas绘制通过多边形标注区域 AI视频项目中需要分析图片&#xff0c;需要前台绘制区域&#xff0c;后端获取坐标然后识别图像&#xff0c;通过canvas 获取点然后连线绘图 HEML代码段 <div class"areaDrawing"><img src"/assets/images/snapPhotos…...

SELECT COUNT(*) 会造成全表扫描吗?

前言 SELECT COUNT(*)会不会导致全表扫描引起慢查询呢&#xff1f; SELECT COUNT(*) FROM SomeTable 网上有一种说法&#xff0c;针对无 where_clause 的 COUNT(*)&#xff0c;MySQL 是有优化的&#xff0c;优化器会选择成本最小的辅助索引查询计数&#xff0c;其实反而性能…...

python考前复习(90题)

文章目录 1.Python特性的是( )。 A. 面向对象 B. 高可移植性 C. 开源、免费 2.临时改变Python语言安装源应当使用的选项是 –index-url 3.Python脚本文件的扩展名为( ) .py 4.安装Python语言的软件包使用的命令是&#xff08; &#xff09; pip install 5 . (单选题)以下哪项是…...

根据SpringBoot Guides完成进行示例学习(详细步骤)

目录 1.打开Spring | Guides官网&#xff0c;或者直接搜索springboot都可 2.选择要学习的内容 3.根据提示的网址&#xff0c;Git到本地 4.将文件用IDEA打开&#xff0c;根据教程完成示例&#xff0c;这里不做细致讲解 5.运行项目 6.在终端查看运行结果 以Scheduling Task…...

waf、yakit和ssh免密登录

WAF安全狗 脏数据适用于所有漏洞绕过waf&#xff0c;但是前提条件垃圾信息必须放在危险信息前&#xff0c;是不能打断原有数据包的结构&#xff0c;不能影响后端对数据包的解析。 以DVWA靶场文件上传为例 新建php文件 上传文件被安全狗拦截 使用bp抓包查看 在数据包Content-…...

【AIGC核心技术剖析】大型语言和视觉助手——LLaVA(论文+源码)

🔥 [新!LLaVA-1.5 在 11 个基准测试上实现了 SoTA,只需对原始 LLaVA 进行简单的修改,利用所有公共数据,在单个 1-A8 节点上在 ~100 天内完成训练,并超越使用数十亿级数据的方法。 LLaVA代表了一种新颖的端到端训练大型多模态模型,结合了视觉编码器和骆马 对于通用的视…...

IBM的WAS简介与基本使用手册

IBM的WAS简介与基本使用手册 1. 基本介绍 WebSphereApplication Server(简称WAS)是IBM的应用服务器 基本结构:单元(cell) ——> 多个节点(node) ——> 多个服务(server) ——> 多个应用(app) 单元是整个分布式网络中一个或多个节点的逻辑分组单元是一个配置概念, 是…...

Deno 快速入门

目录 1、简介 2、安装Deno MacOS下安装 Windows下安装 Linux 下安装 3、创建并运行TypeScript程序 4、内置Web API和Deno命名空间 5、运行时安全 6、导入JavaScript模块 7、远程模块和Deno标准库 8、使用deno.json配置您的项目 9、Node.js API和npm包 10、配置IDE…...

【计算机网络笔记】OSI参考模型基本概念

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…...

ConnectTimeout和ReadTimeout所代表的意义

ConnectTimeout和ReadTimeout所代表的意义 ConnectTimeout 指的是建立连接所用的时间&#xff0c;适用于网络状况正常的情况下&#xff0c;两端连接所用的时间。在java中&#xff0c;网络状况正常的情况下&#xff0c;例如使用HttpClient或者HttpURLConnetion连接时设置参数c…...

使用Python计算平面多边形间最短距离,数据需要从excel表格中导入

使用Python计算平面多边形间最短距离&#xff0c;数据需要从excel表格中导入&#xff0c; * 多边形种类包括&#xff08;圆形、矩形、六边形、五边形、跑道形/胶囊形&#xff09;&#xff0c; * Python代码需要使用gjk算法进行判断两个多边形间是否重叠&#xff0c; * 如果未重…...

华为数通方向HCIP-DataCom H12-831题库(多选题:1-20)

第01题 如图所示,路由器所有的接口开启OSPF,图中标识的ip地址为设备的Loopback0接口的IP地址,R1、R2,R3的Loopback0通告在区域1,R4的Loopback0通告在区域0、R5的Lopback0通告在区域2,下列哪些IP地址之间可以相互Ping通? A、10.0.3.3和10.0.5.5 B、10.0.4.4和10.0.2.2 …...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...