Java设计模式-抽象工厂模式-一次性理解透
1. 抽象工厂模式简介
抽象工厂设计模式是创建型模式之一。抽象工厂模式与工厂模式几乎相似,只是它更像工厂中的工厂。
如果您熟悉Java 中的工厂设计模式
,或看过上一篇我写的“java简单工厂模式”,您会注意到我们有一个工厂类。此工厂类根据提供的输入返回不同的子类,工厂类使用 if-else 或 switch 语句来实现这一点。
但是在抽象工厂模式中,我们摆脱了 if-else
块,并为每个子类设置了一个工厂类。然后是一个抽象工厂类,它将根据输入的工厂类返回子类。起初,这似乎令人困惑,但一旦您看到实现,就很容易掌握和理解工厂和抽象工厂模式之间的细微差别。就像我们的工厂模式帖子一样,我们将使用相同的超类和子类。
2. 抽象工厂模式的原理
抽象工厂模式的角色包括:
- 抽象产品:定义了产品的规范和接口。
- 具体产品:实现了抽象产品的接口,是实际的产品对象。
- 抽象工厂:提供了创建产品的接口,但不负责实现这些接口。
抽象工厂模式通过提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类,实现了产品的创建与使用的分离。这种模式特别适用于那些需要创建多个相关产品对象的场景,如组装电脑时选择CPU、硬盘、内存等配件,或者创建一个包含多种类型产品的产品族,如手机和电脑等电子产品。通过抽象工厂模式,可以更好地管理这些产品的创建和组合,提高系统的可维护性和可扩展性。
3. 抽象工厂的使用场景
下面,整理出了4中典型的关于“抽象工厂模式”的使用场景介绍。
3.1 系统独立于产品创建、组合和表示
当系统需要独立于其产品的创建、组合和表示时,抽象工厂模式可以提供一个统一的接口来创建一系列相关的产品对象,而不必关心具体的实现细节。
3.2 多个产品系列配置
如果一个系统需要由多个产品系列中的一个来配置,抽象工厂模式可以提供一个统一的接口来创建这些产品系列中的对象,确保系统的一致性和可维护性。
3.3 强调一系列相关的产品对象设计
当需要强调一系列相关的产品对象的设计以便进行联合使用时,抽象工厂模式可以确保这些对象一起被正确地创建和使用,以满足特定的功能需求。
3.4 提供产品类库的接口而非实现:
如果提供一个产品类库,而只想显示它们的接口而不是实现时,抽象工厂模式可以通过提供一个统一的接口来创建这些产品对象,使得客户端代码不依赖于具体的实现细节,增加了系统的灵活性和可扩展性。
4. 抽象工厂的代码示例介绍
我们将针对此图进行编程,着重介绍抽象工厂模式。
4.1 抽象工厂设计模式超类和子类
4.1.1 Computer.java
public abstract class Computer {public abstract String getRAM();public abstract String getHDD();public abstract String getCPU();@Overridepublic String toString(){return "RAM= "+this.getRAM()+", HDD="+this.getHDD()+", CPU="+this.getCPU();}
}
4.1.2 PC.java
public class PC extends Computer {private String ram;private String hdd;private String cpu;public PC(String ram, String hdd, String cpu){this.ram=ram;this.hdd=hdd;this.cpu=cpu;}@Overridepublic String getRAM() {return this.ram;}@Overridepublic String getHDD() {return this.hdd;}@Overridepublic String getCPU() {return this.cpu;}}
4.1.3 Server.java
public class Server extends Computer {private String ram;private String hdd;private String cpu;public Server(String ram, String hdd, String cpu){this.ram=ram;this.hdd=hdd;this.cpu=cpu;}@Overridepublic String getRAM() {return this.ram;}@Overridepublic String getHDD() {return this.hdd;}@Overridepublic String getCPU() {return this.cpu;}}
4.2 编写每个子类的工厂类
首先我们需要创建一个抽象工厂接口或抽象类,如上图这个抽象给抽象工厂类叫ComputerAbstractFactory.java
。
public interface ComputerAbstractFactory {public Computer createComputer();
}
注意该createComputer()
方法返回的是超类的一个实例Computer
。现在我们的工厂类将实现此接口并返回各自的子类。
4.2.1 PCFactory.java
public class PCFactory implements ComputerAbstractFactory {private String ram;private String hdd;private String cpu;public PCFactory(String ram, String hdd, String cpu){this.ram=ram;this.hdd=hdd;this.cpu=cpu;}@Overridepublic Computer createComputer() {return new PC(ram,hdd,cpu);}
}
类似地,我们将有一个用于Server子类的工厂类。ServerFactory.java
。
4.2.2 ServerFactory.java
public class ServerFactory implements ComputerAbstractFactory {private String ram;private String hdd;private String cpu;public ServerFactory(String ram, String hdd, String cpu){this.ram=ram;this.hdd=hdd;this.cpu=cpu;}@Overridepublic Computer createComputer() {return new Server(ram,hdd,cpu);}
}
现在我们将创建一个消费者类,为客户端类创建子类提供入口点。ComputerFactory.java
。
public class ComputerFactory {public static Computer getComputer(ComputerAbstractFactory factory){return factory.createComputer();}
}
注意,它是一个简单的类,getComputer
方法接受ComputerAbstractFactory
参数并返回Computer
对象。此时实现应该已经很清晰了。
让我们编写一个简单的测试方法,看看如何使用抽象工厂来获取子类的实例。TestDesignPatterns.java
。
public class TestDesignPatterns {public static void main(String[] args) {testAbstractFactory();}private static void testAbstractFactory() {Computer pc = com.journaldev.design.abstractfactory.ComputerFactory.getComputer(new PCFactory("2 GB","500 GB","2.4 GHz"));Computer server = com.journaldev.design.abstractfactory.ComputerFactory.getComputer(new ServerFactory("16 GB","1 TB","2.9 GHz"));System.out.println("AbstractFactory PC Config::"+pc);System.out.println("AbstractFactory Server Config::"+server);}
}
上述程序的输出将是:
AbstractFactory PC Config::RAM= 2 GB, HDD=500 GB, CPU=2.4 GHz
AbstractFactory Server Config::RAM= 16 GB, HDD=1 TB, CPU=2.9 GHz
5. 抽象工厂模式优缺点
抽象工厂模式的优点包括封装性和解耦性、产品族一致性、易于替换和扩展、提高系统灵活性,而缺点则包括复杂性增加、不易于新增产品、不支持单一产品的变化。
5.1 抽象工厂模式优点
5.1.1 封装性和解耦性:
抽象工厂模式将对象的创建和使用分离,客户端代码不需要关心具体的产品类,从而实现了解耦。客户端代码只需要依赖抽象工厂接口,而不依赖具体产品。
5.1.2 产品族一致性
抽象工厂模式确保一组相关或依赖的产品能够协同工作,因为每个具体工厂类都会创建一整套相关产品。这有助于保持产品之间的一致性。
5.1.3 易于替换和扩展
通过添加新的具体工厂类和产品类,可以轻松扩展抽象工厂模式,而不需要修改现有的客户端代码。这使得系统更易于维护和扩展。
5.1.4 提高系统灵活性
抽象工厂模式允许在运行时切换不同的具体工厂,从而使应用程序更容易适应不同的配置或环境,提高了系统的灵活性。
5.2 抽象工厂模式缺点
5.2.1 复杂性增加:
抽象工厂模式引入了多个抽象类和接口,以及多个具体工厂和产品类,因此可能会增加系统的复杂性。对于小规模应用程序或简单的需求,可能显得过于繁琐。
5.2.2 不易于新增产品
如果需要新增一种产品,抽象工厂模式的修改会比较复杂,因为需要同时修改抽象工厂接口和所有具体工厂类。这可能会导致修改的传播,影响到现有的代码。
5.2.3 不支持单一产品的变化
抽象工厂模式适用于一组相关产品的创建,但如果只有一个产品发生变化,那么整个工厂都需要进行修改,可能不够灵活。
5.3 抽象工厂模式优缺点总结
总的来说,抽象工厂模式适用于需要创建一组相关产品,同时具备高度灵活性和可维护性的场景。
6. JDK 中的抽象工厂设计模式示例
javax.xml.parsers.DocumentBuilderFactory#newInstance()
javax.xml.transform.TransformerFactory#newInstance()
javax.xml.xpath.XPathFactory#newInstance()
7. 总结
抽象工厂模式是一种设计模式,它属于创建型模式,主要用于构建产品族。这种模式当有多个抽象角色时使用,向客户端提供一个接口,使得客户端在不必指定产品的具体情况下,能够创建多个产品族中的产品对象。抽象工厂模式是所有工厂模式中最抽象和最具一般性的一种形态,它针对的是多个产品族结构,而不是单个产品系列结构。
在抽象工厂模式中,每一个工厂负责创建一个产品族,而不是单个产品。这与工厂方法模式不同,后者是针对单个产品系列的。抽象工厂模式的实现原理包括将一组相关或相互依赖的对象抽象成产品族,每个工厂负责创建一个产品族。这种模式允许在不修改客户端代码的情况下增加新的产品族,同时保持了代码的灵活性和可扩展性。
抽象工厂模式的角色包括:
- 抽象产品:定义了产品的规范和接口。
- 具体产品:实现了抽象产品的接口,是实际的产品对象。
- 抽象工厂:提供了创建产品的接口,但不负责实现这些接口。
抽象工厂模式的优点包括:
- 灵活性:可以轻松扩展新的工厂类,支持新的主题或对象类型。
- 可维护性:将对象的创建与使用分离,使代码更清晰、易于维护。
- 可靠性:避免对象的不正确创建和使用,提高代码可靠性。
然而,抽象工厂模式也存在一些缺点,例如不利于添加新种类产品,因为每增加一个新产品种类可能需要修改现有的工厂类,这违反了开闭原则。
相关文章:

Java设计模式-抽象工厂模式-一次性理解透
1. 抽象工厂模式简介 抽象工厂设计模式是创建型模式之一。抽象工厂模式与工厂模式几乎相似,只是它更像工厂中的工厂。 如果您熟悉Java 中的工厂设计模式,或看过上一篇我写的“java简单工厂模式”,您会注意到我们有一个工厂类。此工厂类根据…...

day16-测试自动化之selenium的PO模式
一、PO模式介绍 PO(Page Object)模式是一种在自动化测试中常用的设计模式,将页面的每个元素封装成一个对象,通过操作对象来进行页面的交互。 一般分为六个版本,现在大部分企业都用的V4版本,三层结构…...
Springboot+freemarker大段文本内容动态修改输出,所见即所得
场景:给领导导出数据时,需要给出一个针对专业名词的解释说明,因此会存在有大批量的、大段的文本内容。如果直接写在代码里面,没啥大问题,但是大量的拼接替换、格式样式、后续修改维护等,都不是很方便。如果…...
Kali Linux网络问题解决与静态IP配置技巧
很多用户在使用 Kali Linux 时会遇到无法联网的问题,尤其是在 VMware 虚拟机中。这种情况相当常见,一般都是没有配置DNS服务器或者网卡配置文件的IP和虚拟网络编辑器的IP不一致所导致的,下面我们将探讨如何在 Kali Linux 中配置 DNS 服务和设…...
网络状态码-经验笔记
网络状态码-经验笔记 引言 在网络通信中,HTTP(Hypertext Transfer Protocol)状态码是服务器向客户端(通常是Web浏览器)发送响应时所包含的重要信息之一。 这些状态码指示了客户端请求的结果。 了解并正确使用这些状态…...
c++ 实现 actor 框架
服务端:https://github.com/xukeawsl/coro_actor 客户端:https://github.com/xukeawsl/coro_actor_client...

应对猫咪掉毛挑战,希喂、小米热门宠物空气净化器实测功效PK
随着养宠人群的增多,铲屎官们的需求日益增长,市场上出现了很多品牌的宠物空气净化器。然而,产品质量参差不齐,给消费者选择带来不少困难。劣质宠物空气净化器不仅无法有效去除宠物毛发、皮屑、异味及空气中的有害微粒,…...
0002 保险会计及其特殊性
保险会计是将会计理论专门应用于保险公司的专业会计领域,它是会计学的一个重要分支。作为一个分支,保险会计具有独特的特性,这些特性主要表现在以下几个方面: 产品的无形性:保险产品本质上是一种无形的商品,…...

ChatTTS:终极文本转语音工具,支持API!
ChatTTS:终极文本转语音工具,支持API! 文本转语音(TTS)系统的发展已经取得了长足的进步。从最初的机械化、平坦的声音,到如今听起来令人惊讶的人声,ChatTTS作为这一领域的新成员,旨…...

VUE和Element Plus
1.VUE 1.下载和配置环境 使用vue编程,我们需要使用到的编程软件是vs code,还需要使用node.js,这个的作用就类似于JDK,当我们都下载好之后,winR键打开命令提示符,我们在这里可以查看版本, npm…...
Python学习笔记(五)
""" 演示tuple元组的定义和操作 """# 元组一旦定义完成,就不可修改 # 定义元组 # t1 (1, "Hello", True) # t2 () # 定义空元组 # t3 tuple() #定义空元组 # print(f"t1的类型是:{type(t1)}, 内容是&…...
Linux企业级应用(一)构建企业级Linux应用平台:全面指南
文章目录 构建企业级Linux应用平台:全面指南前言1. Linux企业级应用简介2. 构建企业级网站应用平台使用LNMP架构构建Web服务器部署MySQL数据库主从复制与读写分离 3. 实施虚拟化技术部署KVM虚拟化平台使用LVS和Keepalived实现负载均衡与高可用性 4. 文件系统与分布式…...
LeetCode112 路径总和
前言 题目: 112. 路径总和 文档: 代码随想录——路径总和 编程语言: C 解题状态: 成功解答! 思路 比较简单的一个思路是遍历所有的路径,求和后再查找目标值。但是,最好的方法是一边遍历&#x…...

TI AWR1843 毫米波雷达实物展示
引言 随着自动驾驶、工业自动化以及智能交通系统的快速发展,雷达传感器在现代科技中的重要性日益提升。毫米波雷达凭借其高精度测距、抗干扰能力强等特点,逐渐成为各类感知系统中的关键技术。德州仪器(TI)推出的 AWR1843 毫米波雷…...
前端JS总结(下)之事件操作
目录 前言 事件基础 事件的三部分: 常见的事件: 鼠标事件: 键盘事件: 表单事件: onfocus和onblur:获取焦点和失去焦点 onselect:选中单行文本框/多行文本框中的内容 onchangeÿ…...

如何妙用哈希表来优化遍历查找过程?刷题感悟总结,c++实现
先上题目 题目链接:题目链接 这题我最先想到的就是前缀和a,构造好了以后就遍历每一个[l,r]数组(满足题目要求的连续区间数组),奈何倒数第二个样例时间超限 先给出原思路代码 class Solution { public:int subarray…...
【设计模式】漫谈设计模式
这篇文章里说一下对设计模式的个人的理解。本篇文章更类似于随笔而非技术文档。 设计模式最早是在上个世纪就被人提出来了,如今被奉为圣经,也就是GOF等人写的《设计模式》,其中的设计模式,是指导开发者如何进行开发出高内聚、低耦…...

第N5周:Pytorch文本分类入门
本文为365天深度学习训练营 中的学习记录博客原作者:K同学啊 任务: ●1. 了解文本分类的基本流程 ●2. 学习常用数据清洗方法 ●3. 学习如何使用jieba实现英文分词 ●4. 学习如何构建文本向量 一、前期准备 环境安装 这是一个使用PyTorch实现的简单文…...

SpringBoot 自定义 starter
1. 官方文档 SpringBoot 版本 2.6.13,相关链接 Developing with Spring Boot 1.1 什么是 Starter Starters are a set of convenient dependency descriptors that you can include in your application. You get a one-stop shop for all the Spring and relate…...
TDengine Invalid data format 问题定位
Invalid data format 看语义是数据类型不符,通常这个报错出现在使用行协议写入时。 如果是批量数据写入,想定位是哪条语句的问题,需要查看客户端日志。 如何确定使用的是哪个日志 lsof -p pidof taosadapter | grep taoslog如果没有安装lso…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...

Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...