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…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...

2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...