【三】设计模式~~~创建型模式~~~抽象工厂模式(Java)

news/2024/5/10 9:10:32/文章来源:https://blog.csdn.net/weixin_43304253/article/details/130881412

【学习难度:★★★★☆,使用频率:★★★★★】

3.1. 模式动机

  • 在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法。但是有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。为了更清晰地理解工厂方法模式,需要先引入两个概念:
    • 产品等级结构 :产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
    • 产品族 :在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。
  • 当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式。
  • 抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形态。
  • 抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效率。
    在这里插入图片描述

3.2. 模式定义

        抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。

3.3. 模式结构

        抽象工厂模式包含如下角色:

  • AbstractFactory:抽象工厂,它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
  • ConcreteFactory:具体工厂,它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
  • AbstractProduct:抽象产品,它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
  • Product:具体产品,它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
    在这里插入图片描述

3.4. 时序图

在这里插入图片描述

3.5. 代码分析

SkinFactory接口充当抽象工厂,其子类SpringSkinFactory和SummerSkinFactory充当具体工厂,接口Button、TextField和ComboBox充当抽象产品,其子类SpringButton、SpringTextField、SpringComboBox和SummerButton、SummerTextField、SummerComboBox充当具体产品。
在这里插入图片描述

3.5.1 生产

package com.zyz.demo1;/*** @author zyz* @version 1.0* @data 2023/5/9 22:35* @Description:*/import javafx.scene.control.Skin;/*** 按钮接口:抽象产品*/
interface Button {public void display();
}/*** Spring按钮类:具体产品*/
class SpringButton implements Button {@Overridepublic void display() {System.out.println("显示浅绿色按钮。");}
}/*** Summer按钮类:具体产品*/
class SummerButton implements Button {@Overridepublic void display() {System.out.println("显示浅蓝色按钮。");}
}/*** 文本框接口:抽象产品*/
interface TextField {public void display();
}/*** Spring文本框类:具体产品*/
class SpringTextField implements TextField {@Overridepublic void display() {System.out.println("显示绿色边框文本框。");}
}/*** Summer文本框类:具体产品*/
class SummerTextField implements TextField {@Overridepublic void display() {System.out.println("显示蓝色边框文本框。");}
}/*** 组合框接口:抽象产品*/
interface ComboBox {public void display();
}/*** Spring组合框类:具体产品*/
class SpringComboBox implements ComboBox {@Overridepublic void display() {System.out.println("显示绿色边框组合框。");}
}/*** Summer组合框类:具体产品*/
class SummerComboBox implements ComboBox {@Overridepublic void display() {System.out.println("显示蓝色边框组合框。");}
}/*** 界面皮肤工厂接口:抽象工厂*/
interface SkinFactory{public Button createButton();public TextField createTextField();public ComboBox createComBox();
}/*** Spring皮肤工厂:具体工厂*/
class SpringSkinFactory implements SkinFactory{@Overridepublic Button createButton() {return new SpringButton();}@Overridepublic TextField createTextField() {return new SpringTextField();}@Overridepublic ComboBox createComBox() {return new SpringComboBox();}
}/*** Summer皮肤工厂:具体工厂*/
class SummerSkinFactory implements SkinFactory{@Overridepublic Button createButton() {return new SummerButton();}@Overridepublic TextField createTextField() {return new SummerTextField();}@Overridepublic ComboBox createComBox() {return new SpringComboBox();}
}

3.5.2 客户端

package com.zyz.demo1;/*** @author zyz* @version 1.0* @data 2023/5/9 22:44* @Description:*/
public class Client {public static void main(String[] args) {Button button;TextField textField;ComboBox comboBox;SkinFactory skinFactory;skinFactory = new SpringSkinFactory();button = skinFactory.createButton();textField = skinFactory.createTextField();comboBox = skinFactory.createComBox();button.display();textField.display();comboBox.display();}
}

3.5.3 结果

在这里插入图片描述

3.6. 模式分析

3.7. 实例

同3.5 代码分析

3.8. 优点

  • 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,应用抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用。
  • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,是一种非常实用的设计模式。
  • 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。

3.9. 缺点

  • 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。
  • 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)。

3.10. 适用环境

在以下情况下可以使用抽象工厂模式:

  • 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。
  • 系统中有多于一个的产品族,而每次只使用其中某一产品族。
  • 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
  • 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

3.11. 模式应用

在很多软件系统中需要更换界面主题,要求界面中的按钮、文本框、背景色等一起发生改变时,可以使用抽象工厂模式进行设计。

3.12. 模式扩展

“开闭原则”的倾斜性

  • “开闭原则”要求系统对扩展开放,对修改封闭,通过扩展达到增强其功能的目的。对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:
    • a. 增加产品族:对于增加新的产品族,工厂方法模式很好的支持了“开闭原则”,对于新增加的产品族,只需要对应增加一个新的具体工厂即可,对已有代码无须做任何修改。
    • b. 增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,不能很好地支持“开闭原则”。
  • 抽象工厂模式的这种性质称为“开闭原则”的倾斜性,抽象工厂模式以一种倾斜的方式支持增加新的产品,它为新产品族的增加提供方便,但不能为新的产品等级结构的增加提供这样的方便。
    工厂模式的退化
  • 当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式;当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式。

3.13. 总结

  • 抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。
  • 抽象工厂模式包含四个角色:抽象工厂用于声明生成抽象产品的方法;具体工厂实现了抽象工厂声明的生成抽象产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中;抽象产品为每种产品声明接口,在抽象产品中定义了产品的抽象业务方法;具体产品定义具体工厂生产的具体产品对象,实现抽象产品接口中定义的业务方法。
  • 抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构。
  • 抽象工厂模式的主要优点是隔离了具体类的生成,使得客户并不需要知道什么被创建,而且每次可以通过具体工厂类创建一个产品族中的多个对象,增加或者替换产品族比较方便,增加新的具体工厂和产品族很方便;主要缺点在于增加新的产品等级结构很复杂,需要修改抽象工厂和所有的具体工厂类,对“开闭原则”的支持呈现倾斜性。
  • 抽象工厂模式适用情况包括:一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节;系统中有多于一个的产品族,而每次只使用其中某一产品族;属于同一个产品族的产品将在一起使用;系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

3.14 扩展(读取xml文件)

为了让系统具备良好的灵活性和可扩展性,我们引入了工具类XMLUtil和配置文件,其中,XMLUtil类的代码如下所示:

package com.zyz.demo1.config;import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
/*** @author zyz* @version 1.0* @data 2023/5/9 23:05* @Description:*/
public class XMLUtil {/*** 该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象* @return*/public static Object getBean() {try {String path = "F:\\java学习资料(后端)\\github管理后端学习资料\\后端学习\\设计模式\\代码\\DesignPatterns-Java-Examples\\3. 抽象工厂模式\\src\\main\\resources\\config.xml";//创建文档对象DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = dFactory.newDocumentBuilder();Document doc;doc = builder.parse(new File(path));//获取包含类名的文本节点NodeList nl = doc.getElementsByTagName("className");Node classNode=nl.item(0).getFirstChild();String cName=classNode.getNodeValue();//通过类名生成实例对象并将其返回Class c=Class.forName("com.zyz.demo1."+cName);Object obj=c.newInstance();return obj;}catch(Exception e) {e.printStackTrace();return null;}}
}

配置文件config.xml中存储了具体工厂类的类名,代码如下所示:

<?xml version="1.0"?>
<config><className>SpringSkinFactory</className>
</config>

编写如下客户端测试代码:

package com.zyz.demo1;import com.zyz.demo1.config.XMLUtil;/*** @author zyz* @version 1.0* @data 2023/5/9 23:08* @Description:*/
public class Client1 {public static void main(String[] args) {Button button;TextField textField;ComboBox comboBox;SkinFactory skinFactory;skinFactory = (SkinFactory) XMLUtil.getBean();button = skinFactory.createButton();textField = skinFactory.createTextField();comboBox = skinFactory.createComBox();button.display();textField.display();comboBox.display();}
}

效果
在这里插入图片描述

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

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

相关文章

OJ练习第116题——二进制矩阵中的最短路径(BFS)

二进制矩阵中的最短路径 力扣链接&#xff1a;1091. 二进制矩阵中的最短路径 题目描述 给你一个 n x n 的二进制矩阵 grid 中&#xff0c;返回矩阵中最短 畅通路径 的长度。如果不存在这样的路径&#xff0c;返回 -1 。 二进制矩阵中的 畅通路径 是一条从 左上角 单元格&am…

ORB-LSAM2:ComputeKeyPointsOctTree()提取特征:maxY = iniY + hCell + 6 为怎么是+6而不是+3?

如标题所示&#xff0c;本博客主要讲述 void ORBextractor::ComputeKeyPointsOctTree(vector<vector<KeyPoint>> &allKeypoints){}函数中maxY iniY hCell 6 为怎么是6而不是3&#xff1f; 为了连续性&#xff0c;会介绍一下ComputeKeyPointsOctTree函数&a…

PMP课堂模拟题目及解析(第13期)

121. 项目经理、团队成员以及若干干系人共同参与一次风险研讨会。已经根据风险管理计划生成并提供一份风险报告。若要为各个项目风险进行优先级排序&#xff0c;现在必须执行哪一项分析&#xff1f; A. 定量风险分析 B. 根本原因分析 C. 偏差分析 D. 定性风险分析 122. …

软件系统三基座之一:权限管理

软件系统三基座包含&#xff1a;权限管理、组织架构、用户管理。 何为基座&#xff0c;即是有了这些基础&#xff0c;任一相关的“建筑”就能逐步搭建起来。 万丈高楼平地起 一、为什么要权限管理 权限管理&#xff0c;一般指根据系统设置的安全规则或者安全策略&#xff0c;…

报表控件FastReport使用指南-在Ubuntu LTS中创建PDF文档

FastReport 是功能齐全的报表控件&#xff0c;可以帮助开发者可以快速并高效地为.NET&#xff0c;VCL&#xff0c;COM&#xff0c;ActiveX应用程序添加报表支持&#xff0c;由于其独特的编程原则&#xff0c;现在已经成为了Delphi平台最优秀的报表控件&#xff0c;支持将编程开…

jvm之JMX

写在前面 本文来看先jmx相关内容。 1&#xff1a;jmx介绍 jvm在运行的过程中有很多的信息&#xff0c;比如堆内存&#xff0c;线程数&#xff0c;加载的类信息&#xff0c;CPU的使用量等&#xff0c;如果我们想要将这些信息暴漏让外界获取&#xff0c;该怎么做呢?此时就需要…

池州控股集团财务共享项目启动啦!

近日&#xff0c;由用友网络承建的池州市投资控股集团有限公司财务共享项目启动会成功举办&#xff0c;也标志着池州控股集团财务共享项目正式启动&#xff01;池州控股集团总经理刘俊、用友国资事业部总经理汪发清及其他相关专家和项目组主要成员参加了此次启动会。 池州投控集…

档案馆空气质量在线3D监控系统温湿度方案

档案馆库房八防温湿度空气质量一体化解决方案 档案库房是档案事业发展的基石&#xff0c;其主要任务是集中保管国家机构及个人等在各种形式下形成的具有一定价值和保存价值的各种载体档案&#xff0c;主要包括文书档案、科技档案、会计档案、人事档案、实物档案等。随着我国经济…

Node版本管理器nvm的安装与使用

前言&#xff1a; 多项目新旧项目管理的时候&#xff0c;往往与依赖不同的node版本&#xff0c;不同的版本对其他依赖的安装有一定的影响&#xff0c;因此我们需要对node的版本进行方便快捷管理和切换&#xff0c;如果直接卸载重装对应版本&#xff0c;切换项目再次卸载重装明显…

【泛微ecology_oracle】如何把查询到的单列人力资源id合并成多人力资源格式

如何把查询到的单列人力资源id合并成多人力资源格式 在泛微ecology中&#xff0c;单列人力资源id合并成多人力资源的使用场景在泛微ecology中&#xff0c;在数据库里人员姓名存储形式那如何实现人力资源字段合并多人力资源字段呢&#xff1f; 在泛微ecology中&#xff0c;单列人…

Rancher添加集群报错:Etcd Cluster is not healthy

原因&#xff1a; 有一台虚拟机在升级内核失败后&#xff0c;回滚至快照。但由于快照版本太老旧&#xff0c;和当前的rancher版本不匹配&#xff0c;服务器上的agent等需要清楚后&#xff0c;重新在rancher添加集群&#xff1b;但是只删除了rancher镜像以及agent相关容器&#…

开源开放 生态共建 | openKylin社区单位会员突破200家!

当前&#xff0c;开放、协作、共享的开源模式已成为全球软件技术和产业创新的主导&#xff0c;也为信息技术国产自主化提供了强大助力。openKylin作为中国桌面操作系统开源社区&#xff0c;以聚焦桌面操作系统根技术为核心、以孵化相关领域关键项目为目标、以布道开源文化为抓手…

关闭linux kernel内核的启动log在控制台的输出

要关闭Linux内核的启动日志&#xff0c;你可以通过以下方法之一进行操作&#xff1a; 1. 通过引导加载器配置&#xff1a; 打开引导加载器的配置文件&#xff0c;如GRUB的配置文件 /boot/grub/grub.cfg。 在内核的启动行&#xff08;以 “linux” 或 “kernel” 开头&#xf…

[论文评析]C-Mixup: Improving Generalization in Regression, NeurIPS,2022

C-Mixup: Improving Generalization in Regression 前言C-MixupReferences 前言 Mixup方法是针对分类任务的, 这篇方法相当于时提出了regression版本的Mixup, 实验证实能够大幅提升在regression task上的泛化能力. C-Mixup 是否可以把Mixup直接用于Regression task呢? 在原…

这可能是最全面的Java学习路线了

大家好&#xff0c;我是大彬~ 我本科学的不是计算机&#xff0c;大四开始自学Java&#xff0c;并且拿到了几个互联网中大厂的offer。在学习Java这方面还是比较有经验的&#xff0c;下面我来分享下我整理的Java自学路线。 在这里也提醒学弟学妹们&#xff0c;要尽早确定以后的…

数字档案馆建设指南

数字档案馆建设指南 目 录 1.总体要求 2.管理系统功能要求 3.应用系统开发和服务平台构建 4.数字档案资源建设 5.保障体系建设 1.总体要求 1.1概述 数字档案馆是指各级各类档案馆为适应信息社会日益增长的对档案信息资源管理、利用需求&#xff0c;运用现代信息技术对数字…

【问题记录】postgreSQL使用默认密码导致kdevtmpfsi挖矿病毒注入

起因 postgreSQL我做错了这几件事情 开启了全部IP登陆权限postgreSQL用的是默认用户名和密码用户postgres也没有设置密码&#xff0c;直接用su - postgres就能登陆 不知道是什么原理&#xff0c;反正服务器被侵入&#xff0c;并且注入了病毒文件 1. 基本信息排查 linux服务器…

Kafka实时数据即席查询应用与实践

作者&#xff1a;vivo 互联网搜索团队- Deng Jie Kafka中的实时数据是以Topic的概念进行分类存储&#xff0c;而Topic的数据是有一定时效性的&#xff0c;比如保存24小时、36小时、48小时等。而在定位一些实时数据的Case时&#xff0c;如果没有对实时数据进行历史归档&#xff…

用Typescript 的方式封装Vue3的表单绑定,支持防抖等功能。

Vue3 的父子组件传值、绑定表单数据、UI库的二次封装、防抖等&#xff0c;想来大家都很熟悉了&#xff0c;本篇介绍一种使用 Typescript 的方式进行统一的封装的方法。 基础使用方法 Vue3对于表单的绑定提供了一种简单的方式&#xff1a;v-model。对于使用者来说非常方便&…

镜像二叉树和求二叉树最大深度(java)

镜像二叉树和求二叉树最大深度 镜像二叉树。有些题目叫翻转二叉树。是同一个题。二叉树的最大深度 镜像二叉树。有些题目叫翻转二叉树。是同一个题。 题目描述&#xff1a;给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例&#xff1…