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

Java设计模式-抽象工厂模式-一次性理解透

抽象工厂模式示意图

1. 抽象工厂模式简介

抽象工厂设计模式是创建型模式之一。抽象工厂模式与工厂模式几乎相似,只是它更像工厂中的工厂

如果您熟悉Java 中的工厂设计模式,或看过上一篇我写的“java简单工厂模式”,您会注意到我们有一个工厂类。此工厂类根据提供的输入返回不同的子类工厂类使用 if-else 或 switch 语句来实现这一点

但是在抽象工厂模式中,我们摆脱了 if-else 块,并为每个子类设置了一个工厂类。然后是一个抽象工厂类,它将根据输入的工厂类返回子类。起初,这似乎令人困惑,但一旦您看到实现,就很容易掌握和理解工厂和抽象工厂模式之间的细微差别。就像我们的工厂模式帖子一样,我们将使用相同的超类和子类。

2. 抽象工厂模式的原理

在这里插入图片描述
抽象工厂模式的角色包括:‌

  1. 抽象产品:‌定义了产品的规范和接口。‌
  2. 具体产品:‌实现了抽象产品的接口,‌是实际的产品对象。‌
  3. 抽象工厂:‌提供了创建产品的接口,‌但不负责实现这些接口。‌

抽象工厂模式通过提供一个创建一系列相关或相互依赖对象的接口,‌而无需指定它们具体的类,‌实现了产品的创建与使用的分离。‌这种模式特别适用于那些需要创建多个相关产品对象的场景,‌如组装电脑时选择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. 总结

抽象工厂模式是一种设计模式,‌它属于创建型模式,‌主要用于构建产品族。‌这种模式当有多个抽象角色时使用,‌向客户端提供一个接口,‌使得客户端在不必指定产品的具体情况下,‌能够创建多个产品族中的产品对象。‌抽象工厂模式是所有工厂模式中最抽象和最具一般性的一种形态,‌它针对的是多个产品族结构,‌而不是单个产品系列结构。‌

在抽象工厂模式中,‌每一个工厂负责创建一个产品族,‌而不是单个产品。‌这与工厂方法模式不同,‌后者是针对单个产品系列的。‌抽象工厂模式的实现原理包括将一组相关或相互依赖的对象抽象成产品族,‌每个工厂负责创建一个产品族。‌这种模式允许在不修改客户端代码的情况下增加新的产品族,‌同时保持了代码的灵活性和可扩展性。‌

抽象工厂模式的角色包括:‌

  1. 抽象产品:‌定义了产品的规范和接口。‌
  2. 具体产品:‌实现了抽象产品的接口,‌是实际的产品对象。‌
  3. 抽象工厂:‌提供了创建产品的接口,‌但不负责实现这些接口。‌

抽象工厂模式的优点包括:‌

  1. 灵活性:‌可以轻松扩展新的工厂类,‌支持新的主题或对象类型。‌
  2. 可维护性:‌将对象的创建与使用分离,‌使代码更清晰、‌易于维护。‌
  3. 可靠性:‌避免对象的不正确创建和使用,‌提高代码可靠性。‌

然而,‌抽象工厂模式也存在一些缺点,‌例如不利于添加新种类产品,‌因为每增加一个新产品种类可能需要修改现有的工厂类,‌这违反了开闭原则。‌

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 爬虫配置代理:保护隐私有效地抓取数据
  • C#多线程并发编程深度探索:解锁async、await、Task与lock等关键字的奥秘
  • 【生成式人工智能-八-大型语言模型的能力评估】
  • JAVA集中学习第五周学习记录(二)
  • Spring Boot 快速入门样例【后端 3】
  • Linux Shell实例
  • Python 通过UDP传输超过64k的信息
  • 深度学习入门案例:运用神经网络实现价格分类
  • linux中守护进程管理方式
  • 【学习笔记】Day 14
  • 和等于 k 的最长子数组长度(LeetCode)
  • MySQL windows版本安装
  • How do you implement OpenAI GPT-3 Api Client in PHP?
  • 古希腊掌管类型转换的神 boost::lexical_cast
  • 掌握Objective-C中的NSSpellServer:拼写检查的艺术
  • 【EOS】Cleos基础
  • 【跃迁之路】【477天】刻意练习系列236(2018.05.28)
  • 77. Combinations
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • Linux链接文件
  • PaddlePaddle-GitHub的正确打开姿势
  • spring + angular 实现导出excel
  • Spring Cloud Feign的两种使用姿势
  • SQL 难点解决:记录的引用
  • Sublime Text 2/3 绑定Eclipse快捷键
  • webpack项目中使用grunt监听文件变动自动打包编译
  • 扑朔迷离的属性和特性【彻底弄清】
  • 前端技术周刊 2018-12-10:前端自动化测试
  • 前嗅ForeSpider采集配置界面介绍
  • nb
  • raise 与 raise ... from 的区别
  • 浅谈sql中的in与not in,exists与not exists的区别
  • 说说我为什么看好Spring Cloud Alibaba
  • ​2021半年盘点,不想你错过的重磅新书
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • (~_~)
  • (HAL库版)freeRTOS移植STMF103
  • (MATLAB)第五章-矩阵运算
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (附源码)ssm失物招领系统 毕业设计 182317
  • (区间dp) (经典例题) 石子合并
  • (游戏设计草稿) 《外卖员模拟器》 (3D 科幻 角色扮演 开放世界 AI VR)
  • (终章)[图像识别]13.OpenCV案例 自定义训练集分类器物体检测
  • .a文件和.so文件
  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现
  • .net framework 4.0中如何 输出 form 的name属性。
  • .net反编译工具
  • .NET设计模式(2):单件模式(Singleton Pattern)
  • .net实现头像缩放截取功能 -----转载自accp教程网
  • .net使用excel的cells对象没有value方法——学习.net的Excel工作表问题
  • .NET周刊【7月第4期 2024-07-28】
  • @ 代码随想录算法训练营第8周(C语言)|Day53(动态规划)
  • @DependsOn:解析 Spring 中的依赖关系之艺术
  • [ vulhub漏洞复现篇 ] JBOSS AS 5.x/6.x反序列化远程代码执行漏洞CVE-2017-12149
  • [2013][note]通过石墨烯调谐用于开关、传感的动态可重构Fano超——