最简单的设计模式,抽象工厂模式,是否属于过度设计?

devtools/2024/11/19 8:21:41/

在这里插入图片描述

目录

    • 一、不采用抽象工厂模式
      • 1、抽象产品
      • 2、具体产品
      • 3、测试类 ~ 不用抽象工厂模式
      • 4、新增笔记本的CPU和内存
      • 5、在Client测试类中新增:
    • 二、那么,如果采用抽象工厂模式优化上面代码,要怎么做呢?
      • 抽象工厂模式通常包括以下几个部分:
      • 1、抽象工厂接口
      • 2、具体工厂类
      • 3、测试类 ~ 抽象工厂模式
      • 4、新增笔记本电脑的具体工厂类
      • 5、在测试类中新增
    • 三、新增具体产品时,扩展新的工厂类再在客户端中创建工厂类代码 和 在客户端中直接创建实例代码,有什么本质区别吗?
      • 1、解耦
      • 2、扩展性
      • 3、单一职责原则
    • 四、在jdk源码中,哪些地方应用了抽象工厂模式
      • 1、DocumentBuilderFactory 在 JDK 中的应用
      • 2、SAXParserFactory 的应用
      • 3、这些应用解决了什么问题?
      • 4、总结

在日常开发中,我们往往忽视了设计模式的重要性。这可能是因为项目时间紧迫,或者对设计模式理解不深。其实,很多时候我们可能在不经意间已经使用了某些模式。

重要的是要有意识地学习和应用,让代码更加优雅和高效。也许是时候重新审视我们的编程实践,将设计模式融入其中了。

先从最简单的设计模式抽象工厂模式】走起,让我们一起“重学设计模式”。

灵魂拷问:新增具体产品时,扩展新的工厂类再在客户端中创建工厂类代码 和 在客户端中直接创建实例代码,有什么本质区别吗?

一、不采用抽象工厂模式

假设你正在设计一套系统,该系统用于创建不同配置的电脑,例如PC和服务器。每种类型的电脑都有不同的CPU和内存。

1、抽象产品

/*** 抽象产品 - CPU*/
public interface CPU {void compute();
}/*** 抽象产品 - 内存*/
public interface Memory {void store();
}

2、具体产品

/*** 具体产品 - PC 的 CPU 实现*/
public class PCCPU implements CPU {@Overridepublic void compute() {System.out.println("PC CPU is computing");}
}/*** 具体产品 - PC 的内存实现*/
public class PCMemory implements Memory {@Overridepublic void store() {System.out.println("PC Memory is storing data");}
}/*** 具体产品 - 服务器的 CPU 实现*/
public class ServerCPU implements CPU {@Overridepublic void compute() {System.out.println("Server CPU is computing with high performance");}
}/*** 具体产品 - 服务器的内存实现*/
public class ServerMemory implements Memory {@Overridepublic void store() {System.out.println("Server Memory is storing data with high capacity");}
}

3、测试类 ~ 不用抽象工厂模式

/*** 不用抽象工厂模式*/
public class Client {public static void main(String[] args) {// 创建 PC 的组件CPU pcCPU = new PCCPU();Memory pcMemory = new PCMemory();pcCPU.compute();pcMemory.store();// 创建 服务器 的组件CPU serverCPU = new ServerCPU();Memory serverMemory = new ServerMemory();serverCPU.compute();serverMemory.store();}
}

4、新增笔记本的CPU和内存

/*** 具体产品 - 新增笔记本电脑的 CPU 实现*/
public class LaptopCPU implements CPU {@Overridepublic void compute() {System.out.println("Laptop CPU is computing efficiently");}
}/*** 具体产品 - 笔记本电脑的内存实现*/
public class LaptopMemory implements Memory {@Overridepublic void store() {System.out.println("Laptop Memory is storing data efficiently");}
}

5、在Client测试类中新增:

// 创建笔记本的
CPU laptopCPU = new LaptopCPU();
laptopCPU.compute();
LaptopMemory laptopMemory = new LaptopMemory();
laptopMemory.store();

还是很方便的。

二、那么,如果采用抽象工厂模式优化上面代码,要怎么做呢?

抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,旨在提供一个接口,用于创建相关或依赖对象的家族,而无需指定它们的具体类。通过抽象工厂模式,客户端可以通过接口创建一系列相关对象,而无需知道这些对象的具体实现。

抽象工厂模式通常包括以下几个部分:

  1. 抽象工厂接口(Abstract Factory): 定义创建产品的接口。
  2. 具体工厂类(Concrete Factory): 实现抽象工厂接口,生成具体的产品。
  3. 抽象产品接口(Abstract Product): 定义产品的接口。
  4. 具体产品类(Concrete Product): 实现具体的产品。
  5. 客户端(Client): 通过工厂接口来使用产品,而不依赖于具体产品的实现。

1、抽象工厂接口

/*** 抽象工厂*/
public interface ComputerFactory {CPU createCPU();Memory createMemory();
}

2、具体工厂类

/*** 具体工厂 - PC 工厂*/
public class PCFactory implements ComputerFactory {@Overridepublic CPU createCPU() {return new PCCPU();}@Overridepublic Memory createMemory() {return new PCMemory();}
}/*** 具体工厂 - 服务器工厂*/
public class ServerFactory implements ComputerFactory {@Overridepublic CPU createCPU() {return new ServerCPU();}@Overridepublic Memory createMemory() {return new ServerMemory();}
}

3、测试类 ~ 抽象工厂模式

public class AbstractFactoryClient {public static void main(String[] args) {// 使用 PC 工厂创建 PC 组件ComputerFactory pcFactory = new PCFactory();CPU pcCPU = pcFactory.createCPU();Memory pcMemory = pcFactory.createMemory();pcCPU.compute();pcMemory.store();// 使用服务器工厂创建服务器组件ComputerFactory serverFactory = new ServerFactory();CPU serverCPU = serverFactory.createCPU();Memory serverMemory = serverFactory.createMemory();serverCPU.compute();serverMemory.store();}
}

使用抽象工厂模式时,新增笔记本电脑,如何实现?

4、新增笔记本电脑的具体工厂类

public class LaptopFactory implements ComputerFactory {@Overridepublic CPU createCPU() {return new LaptopCPU();}@Overridepublic Memory createMemory() {return new LaptopMemory();}
}

5、在测试类中新增

// 使用笔记本工厂
ComputerFactory laptopFactory = new LaptopFactory();
CPU laptopCPU = laptopFactory.createCPU();
Memory laptopMemory = laptopFactory.createMemory();laptopCPU.compute();
laptopMemory.store();

三、新增具体产品时,扩展新的工厂类再在客户端中创建工厂类代码 和 在客户端中直接创建实例代码,有什么本质区别吗?

1、解耦

问题: 在不使用抽象工厂模式的实现中,客户端代码(Client)直接依赖于具体的产品类(如 PCCPU、PCMemory、ServerCPU 等)。当需要增加新类型的电脑或更改现有的电脑配置时,客户端代码必须修改。

抽象工厂模式引入了工厂接口(ComputerFactory),客户端通过工厂接口创建对象,而不是直接实例化具体类。这样客户端与具体的产品实现解耦,客户端不需要知道具体的产品类名,只需要依赖工厂接口。代码更加灵活,可以支持不同的产品家族(PC、服务器、笔记本、工作站等)而无需修改客户端代码。

产品创建逻辑都集中在具体工厂中,客户端只关心如何使用产品,而不关心它们是如何创建的。

2、扩展性

问题: 如果要在不使用工厂模式的代码中增加一个新产品(例如,平板电脑的CPU和内存),需要修改客户端代码,增加新产品的实例化逻辑。这违反了开闭原则(对扩展开放,对修改关闭)。

抽象工厂模式允许我们通过创建新的工厂(例如 LaptopFactory)来生成新产品,而无需修改客户端代码。只需在新工厂中提供相应的产品(CPU和Memory),然后将工厂传递给客户端。

支持开闭原则: 新增产品只需增加新的工厂类,不需要修改已有代码,减少了风险和维护成本。

方便维护: 如果产品发生变化(比如某种CPU规格变动),只需要在工厂中修改,不必修改所有调用代码,系统的灵活性显著提高。

3、单一职责原则

问题: 客户端代码不仅负责业务逻辑,还负责产品的创建逻辑,违反了单一职责原则。

在客户端中创建工厂类:客户端的职责更加单一,只负责业务逻辑处理,产品的创建则完全由工厂负责。通过将产品的创建与使用分离,代码变得更加清晰、职责分明。

优点: 遵循单一职责原则,产品创建逻辑集中在工厂中,客户端只处理与产品的使用有关的业务逻辑。

四、在jdk源码中,哪些地方应用了抽象工厂模式

在 JDK 的源码中,抽象工厂模式被广泛应用于创建不同类型的对象家族。

一个典型的例子是 javax.xml.parsers.DocumentBuilderFactory 和 javax.xml.parsers.SAXParserFactory,它们都是 JDK 中使用抽象工厂模式的具体实现。这些工厂用于创建与 XML 解析相关的对象,如 DocumentBuilder 和 SAXParser,而客户端不需要关心这些对象的具体实现。

1、DocumentBuilderFactory 在 JDK 中的应用

(1)抽象工厂类:DocumentBuilderFactory

DocumentBuilderFactory 是一个抽象工厂,用于创建 DocumentBuilder,它负责解析 XML 文档。

newInstance() 方法会返回一个具体的工厂实现(如 org.apache.xerces.jaxp.DocumentBuilderFactoryImpl),该工厂实现负责创建具体的 DocumentBuilder 对象。

package javax.xml.parsers;public abstract class DocumentBuilderFactory {// 用于创建 DocumentBuilder 实例public abstract DocumentBuilder newDocumentBuilder() throws ParserConfigurationException;// 工厂方法,用于获取 DocumentBuilderFactory 的实例public static DocumentBuilderFactory newInstance() {return FactoryFinder.find(DocumentBuilderFactory.class, "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");}
}

(2)具体工厂类:DocumentBuilderFactoryImpl

DocumentBuilderFactoryImpl 是 DocumentBuilderFactory 的一个具体实现,它定义了如何创建 DocumentBuilder。

newDocumentBuilder() 返回一个 DocumentBuilderImpl 实例,具体负责解析 XML。

package org.apache.xerces.jaxp;public class DocumentBuilderFactoryImpl extends DocumentBuilderFactory {@Overridepublic DocumentBuilder newDocumentBuilder() throws ParserConfigurationException {return new DocumentBuilderImpl();}
}

(3)客户端使用

在客户端代码中,使用 DocumentBuilderFactory 创建 DocumentBuilder 对象,而不需要关心具体实现。

通过 DocumentBuilderFactory.newInstance(),客户端获取了一个具体的 DocumentBuilderFactory 实例,然后使用该工厂创建 DocumentBuilder 对象。

客户端不关心 DocumentBuilder 的具体实现,只依赖于抽象工厂接口,符合抽象工厂模式的设计思想。

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;public class XMLParserExample {public static void main(String[] args) {try {// 获取 DocumentBuilderFactory 实例(抽象工厂)DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();// 使用工厂创建 DocumentBuilder(具体产品)DocumentBuilder builder = factory.newDocumentBuilder();// 使用 DocumentBuilder 解析 XML 文档// 示例代码忽略了具体 XML 文件的解析逻辑System.out.println("DocumentBuilder created successfully!");} catch (Exception e) {e.printStackTrace();}}
}

2、SAXParserFactory 的应用

SAXParserFactory 是 JDK 中另一个典型的抽象工厂模式实现,它用于创建 SAXParser 对象,解析 XML 文档。

(1)抽象工厂类:SAXParserFactory

SAXParserFactory 是抽象工厂类,定义了创建 SAXParser 的方法。

package javax.xml.parsers;public abstract class SAXParserFactory {// 创建 SAXParser 的抽象方法public abstract SAXParser newSAXParser() throws ParserConfigurationException, SAXException;// 获取 SAXParserFactory 实例public static SAXParserFactory newInstance() {return FactoryFinder.find(SAXParserFactory.class, "org.apache.xerces.jaxp.SAXParserFactoryImpl");}
}

(2)具体工厂类:SAXParserFactoryImpl

SAXParserFactoryImpl 是 SAXParserFactory 的具体实现,负责创建 SAXParser。

package org.apache.xerces.jaxp;public class SAXParserFactoryImpl extends SAXParserFactory {@Overridepublic SAXParser newSAXParser() throws ParserConfigurationException, SAXException {return new SAXParserImpl();}
}

(3)客户端使用

客户端通过 SAXParserFactory 来创建 SAXParser,解析 XML 文档。

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;public class SAXParserExample {public static void main(String[] args) {try {// 获取 SAXParserFactory 实例(抽象工厂)SAXParserFactory factory = SAXParserFactory.newInstance();// 使用工厂创建 SAXParser(具体产品)SAXParser parser = factory.newSAXParser();// 使用 SAXParser 解析 XML 文档// 示例代码忽略了具体 XML 文件的解析逻辑System.out.println("SAXParser created successfully!");} catch (Exception e) {e.printStackTrace();}}
}

3、这些应用解决了什么问题?

解耦客户端与具体实现: 客户端代码不需要知道 DocumentBuilder 或 SAXParser 的具体实现类,只依赖于抽象工厂类和抽象产品类。这样,XML 解析库可以随时切换实现(例如从 Apache Xerces 切换到其他实现),而无需修改客户端代码。

易于扩展: 当需要增加新的 DocumentBuilder 或 SAXParser 实现时,只需增加新的工厂类,而不需要修改客户端。通过使用抽象工厂模式,可以很容易地扩展和适应新的需求。

集中控制对象创建: 使用工厂类来管理对象的创建,统一了对象的创建逻辑,避免了客户端直接负责实例化的复杂性,使代码更加灵活和可维护。

4、总结

在 JDK 中,诸如 DocumentBuilderFactory 和 SAXParserFactory 的类广泛应用了抽象工厂模式。这种模式确保了客户端代码与具体实现的解耦,并增强了系统的可扩展性和灵活性。通过使用抽象工厂模式,JDK 能够在不同的 XML 解析器之间自由切换,而不影响客户端代码。

👉 GPT功能:

  1. GPT-4o知识问答:世界目前最强AI大模型,没有之一
  2. 最强代码大模型Code Copilot:代码自动补全、代码优化建议、代码重构等
  3. DALL-E AI绘画:AI绘画 + 剪辑 = 自媒体新时代
  4. 私信哪吒,直接使用GPT-4o

在这里插入图片描述


🏆文章收录于:100天精通Java从入门到就业

全网最细Java零基础手把手入门教程,系列课程包括:Java基础、Java8新特性、Java集合、高并发、性能优化等,适合零基础和进阶提升的同学。

🏆哪吒多年工作总结:Java学习路线总结,搬砖工逆袭Java架构师

华为OD机试 2023B卷题库疯狂收录中,刷题点这里

刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。

点击下方名片,回复1024,获取《10万字208道Java经典面试题总结(2024修订版).pdf 》

在这里插入图片描述


http://www.ppmy.cn/devtools/135161.html

相关文章

etcd defrag

场景 prometheus监控告警,告警信息如下 etcd cluster "kube-etcd": database size in use on instance xx is 33.45% of the actual allocated disk space, please run defragmentation (e.g. etcdctl defrag) to retrieve the unused fragmented disk space.处理…

【大语言模型】ACL2024论文-15 大型语言模型中的最佳解释推断

【大语言模型】ACL2024论文-15 大型语言模型中的最佳解释推断 目录 文章目录 【大语言模型】ACL2024论文-15 大型语言模型中的最佳解释推断目录摘要研究背景问题与挑战如何解决创新点算法模型实验效果推荐阅读指数:★★★★☆后记 大型语言模型中的最佳解释推断 摘…

刘艳兵-DBA037-在ASM实例中,如下哪个参数是必须的?

在ASM实例中,如下哪个参数是必须的? A INSTANCE_NAME B ASM_POWER_LIMIT C ASM_DISKGROUPS D INSTANCE_TYPE 答: D INSTANCE_TYPE 选项分析: A. INSTANCE_NAME - 这不是ASM实例特有的必需参数,但它用于…

机器学习(1)

一、机器学习 机器学习(Machine Learning, ML)是人工智能(Artificial Intelligence, AI)的一个分支,它致力于开发能够从数据中学习并改进性能的算法和模型。机器学习的核心思想是通过数据和经验自动优化算法&#xff…

51单片机--- 矩阵按键仿真

51单片机--- 矩阵按键仿真 实验目标:51单片机对矩阵按键进行扫描,将键值显示在数码管上 实验步骤: 在Proteus里画出原理图 在Keil里用C语言编写程序 在Proteus中导入HEX文件,启动仿真 矩阵按键(Matrix Keypad)是一种通过行列交叉方式排列的按键输入设备,广泛应用于…

Java学习教程,从入门到精通,Java 接口(Interface)语法知识点及案例代码(33)

Java 接口(Interface)语法知识点及案例代码 一、接口的基本概念 接口(Interface)是Java中一种引用数据类型,类似于类,但它只能包含常量、方法签名和嵌套类型。接口不能包含实例变量或方法的实现&#xff…

SpringBoot源码解析(四):解析应用参数args

SpringBoot源码系列文章 SpringBoot源码解析(一):SpringApplication构造方法 SpringBoot源码解析(二):引导上下文DefaultBootstrapContext SpringBoot源码解析(三):启动开始阶段 SpringBoot源码解析(四):解析应用参数args 目录…

【杂谈】无人机测绘技术知识

无人机测绘技术知识 随着科技技术的不断进步和低空经济的快速推进,无人机技术已经从最初的军事侦察、航拍娱乐,逐渐深入到各个行业领域,其中无人机测绘技术(航空摄影测量)更是凭借其高效、精准、灵活的特性&#xff0…