【设计模式】工厂模式(创建型)⭐⭐⭐

文章目录

  • 1.概念
    • 1.1 什么是工厂模式
    • 1.2 优点与缺点
  • 2.实现方式
    • 2.1 简单工厂模式(Simple Factory)
    • 2.2 简单工厂模式缺点
    • 2.3 抽象工厂模式(Abstract Factory Pattern)
  • 3. Java 哪些地方用到了工厂模式
  • 4. Spring 哪些地方用到了工厂模式

1.概念

1.1 什么是工厂模式

工厂模式属于创建型模式。它的主要目的是提供一个创建对象的接口,而不直接实例化对象。这样可以将对象的创建和使用分离,降低系统的耦合度,提高系统的灵活性和可扩展性。

1.2 优点与缺点

优点:
1.降低了系统中对象的耦合度,提高了系统的灵活性。
2.增加了系统的可扩展性,当增加新的产品时,只需扩展一个工厂类即可。
3.隔离了具体产品的创建,使得代码符合单一职责原则。
缺点:
1.增加了系统的复杂度,因为引入了新的工厂类层次。
2.如果产品等级结构过于复杂,那么工厂方法模式的类层次也会相当复杂。

2.实现方式

2.1 简单工厂模式(Simple Factory)

① 定义产品接口或抽象类

public interface Product {void operate();
}

② 实现具体产品类:接着,我们创建具体的产品类,它们实现了产品接口或继承了抽象类。

public class ConcreteProductA implements Product {@Overridepublic void operate() {System.out.println("ConcreteProductA operates.");}
}public class ConcreteProductB implements Product {@Overridepublic void operate() {System.out.println("ConcreteProductB operates.");}
}

③ 创建工厂类:然后,我们创建一个工厂类,它提供一个静态方法来创建产品对象。工厂方法根据传入的参数来决定创建哪个具体产品类的实例。

public class SimpleFactory {public static Product createProduct(String type) {if ("A".equals(type)) {return new ConcreteProductA();} else if ("B".equals(type)) {return new ConcreteProductB();}return null;}
}

④ 客户端代码:最后,客户端代码通过调用工厂类的静态方法来获取产品实例,而不是直接创建产品对象。

public class Client {public static void main(String[] args) {Product productA = SimpleFactory.createProduct("A");Product productB = SimpleFactory.createProduct("B");productA.operate();productB.operate();}
}

这种实现方式使得客户端代码与具体产品类的实现解耦,提高了系统的灵活性和可扩展性。如果需要增加新的产品类,只需要扩展新的具体产品类,并在工厂类中增加相应的创建逻辑,而不需要修改客户端代码。

2.2 简单工厂模式缺点

违反开闭原则:简单工厂模式的工厂方法集中了所有产品的创建逻辑。当需要增加新的产品时,必须修改工厂方法来实现新的逻辑,这违反了开闭原则(软件实体应该对扩展开放,对修改关闭)。
工厂方法单一职责原则:随着产品种类增加,工厂方法会变得越来越复杂,包含大量的条件分支语句。这使得工厂类承担了过多的责任,违反了单一职责原则(一个类应该只有一个引起它变化的原因)。
扩展困难:由于工厂类集中了所有产品的创建逻辑,当产品种类很多时,工厂类会变得非常庞大,难以维护和扩展。
依赖集中:客户端代码依赖于工厂类,如果工厂类发生变化,可能会影响到客户端代码。
不利于产品类的解耦:虽然简单工厂模式将客户端的创建逻辑和产品类的实现解耦,但是产品类和工厂类之间的耦合度仍然较高,因为工厂类需要知道所有产品类的具体实现。
不利于反射和依赖注入:由于工厂类内部硬编码了产品类的创建逻辑,这使得在运行时难以通过反射或依赖注入的方式来动态地创建和替换产品对象。

2.3 抽象工厂模式(Abstract Factory Pattern)

① 定义抽象工厂接口:声明了一组用于创建抽象产品对象的方法。

public interface AbstractFactory {AbstractProductA createProductA();AbstractProductB createProductB();
}

② 实现具体工厂类:实现了抽象工厂接口,每个具体工厂都负责创建自己产品系列中的对象。

public class ConcreteFactory1 implements AbstractFactory {@Overridepublic AbstractProductA createProductA() {return new ConcreteProductA1();}@Overridepublic AbstractProductB createProductB() {return new ConcreteProductB1();}
}public class ConcreteFactory2 implements AbstractFactory {@Overridepublic AbstractProductA createProductA() {return new ConcreteProductA2();}@Overridepublic AbstractProductB createProductB() {return new ConcreteProductB2();}
}

③ 定义抽象产品接口:声明了产品的公共接口。

public interface AbstractProductA {void usefulFunctionA();
}public interface AbstractProductB {void usefulFunctionB();
}

④ 实现具体产品类:实现了抽象产品接口,每个具体产品都属于一个产品系列。

public class ConcreteProductA1 implements AbstractProductA {@Overridepublic void usefulFunctionA() {// 具体实现}
}public class ConcreteProductA2 implements AbstractProductA {@Overridepublic void usefulFunctionA() {// 具体实现}
}public class ConcreteProductB1 implements AbstractProductB {@Overridepublic void usefulFunctionB() {// 具体实现}
}public class ConcreteProductB2 implements AbstractProductB {@Overridepublic void usefulFunctionB() {// 具体实现}
}

⑤ 客户端代码:客户端通过抽象工厂接口来创建产品,而不需要关心具体工厂和产品的实现细节。

public class Client {public static void main(String[] args) {AbstractFactory factory1 = new ConcreteFactory1();AbstractProductA productA1 = factory1.createProductA();AbstractProductB productB1 = factory1.createProductB();productA1.usefulFunctionA();productB1.usefulFunctionB();AbstractFactory factory2 = new ConcreteFactory2();AbstractProductA productA2 = factory2.createProductA();AbstractProductB productB2 = factory2.createProductB();productA2.usefulFunctionA();productB2.usefulFunctionB();}
}

3. Java 哪些地方用到了工厂模式

Java AWT(Abstract Window Toolkit):AWT中的 Button, TextField, Label 等组件在不同的操作系统上会有不同的外观和行为。AWT使用抽象工厂模式来创建这些组件,以便它们可以根据运行平台的不同而自动适配。
Java Swing:与AWT类似,Swing组件也使用了抽象工厂模式来创建组件,以便它们可以根据不同的Look and Feel(比如Windows, Motif, Metal等)来改变外观。
JDBC(Java Database Connectivity):JDBC使用抽象工厂模式来创建数据库连接。DriverManager 类充当抽象工厂,它根据URL的不同来创建不同数据库的连接(例如MySQL, Oracle, SQL Server等)。
Java XML解析:在解析XML文档时,可以使用抽象工厂模式来创建不同的解析器。例如,可以根据需要创建SAX或DOM解析器的实例。
Java国际化(Internationalization, I18N):在处理国际化时,可以使用抽象工厂模式来创建不同语言环境的资源包。
Java Logging API:Java的日志记录框架(如Log4j, SLF4J等)通常使用抽象工厂模式来创建日志记录器实例,以便可以根据配置动态地选择不同的日志实现。
Spring Framework:Spring框架广泛使用了抽象工厂模式来创建bean。例如,BeanFactory 和 ApplicationContext 都是抽象工厂,它们负责根据配置文件或注解来创建和管理bean的生命周期。
Java ImageIO:ImageIO 类是一个抽象工厂,用于创建图像输入/输出处理的流。它可以根据图像格式(如JPEG, PNG, GIF等)来创建相应的图像读取器和写入器。

4. Spring 哪些地方用到了工厂模式

BeanFactory:BeanFactory 是Spring中最基本的抽象,它是一个工厂模式的实现,负责创建和管理bean的生命周期。BeanFactory 根据配置信息来创建bean,并且可以管理bean之间的依赖关系。
ApplicationContext:ApplicationContext 是 BeanFactory 的超集,它也实现了工厂模式。与 BeanFactory 相比,ApplicationContext 提供了更多的功能,如事件传播、资源加载、国际化消息处理等。
FactoryBean:Spring提供了一个名为 FactoryBean 的接口,允许开发者创建自己的工厂来生成复杂的对象。实现这个接口的类可以作为工厂,Spring容器会调用其 getObject 方法来获取bean实例。
ObjectFactory:ObjectFactory 是一个简单的工厂接口,它只有一个方法 getObject。这个接口通常用于延迟加载场景,可以在需要的时候才创建对象。
JdbcTemplate 和数据源:Spring的 JdbcTemplate 类依赖于数据源来获取数据库连接。数据源的创建通常是通过工厂模式来实现的,可以根据配置动态地创建不同类型的数据源实例。
事务管理:Spring的事务管理也使用了工厂模式。例如,TransactionManager 是一个抽象工厂,它根据配置来创建和管理事务。
AOP代理创建:Spring的AOP框架使用工厂模式来创建代理对象。根据配置的不同,Spring可以创建JDK动态代理或CGLIB代理。
消息服务:Spring的JMS模块使用工厂模式来创建消息生产者和消费者。
资源加载:Spring的 ResourceLoader 是一个抽象工厂,它根据资源路径来创建 Resource 对象。
事件发布:Spring的事件发布机制也使用了工厂模式,ApplicationEventPublisher 负责创建和发布事件。
Spring框架的设计哲学之一就是依赖注入(DI),它允许将对象之间的依赖关系外部化,由容器来管理。工厂模式是实现依赖注入的关键机制之一,它允许Spring容器根据配置来创建和管理对象,从而提供了极大的灵活性和扩展性。

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

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

相关文章

【SpringBoot】SpringBoot同时可以处理多少请求

目录 问题Web三大容器三者区别TomcatJetty小结 最大连接数和最大等待数同时处理请求数拓展:设置Web容器设置容器为Jetty设置容器为Undertow 问题 之前看到过一个面试题:SpringBoot同时可以处理多少请求? 准确的来说,Spring Boot…

mysql聚簇索引

1.聚簇索引是物理索引,数据在表里是按顺序存储的,物理上是连续的,一般选主键id作为聚簇索引,且一张表里只能有一个聚簇索引。 2.只有InnoDB支持聚簇索引。 3.非聚簇索引是逻辑索引,将数据的某个字段抽取出来组成独立的…

JVM常用概念之锁粗化和循环

1.什么是锁粗化 锁粗化一般指有效地合并几个相邻的锁定块,从而减少锁定开销。如下述代码所示: 锁粗化前代码: synchronized (obj) {// statements 1 } synchronized (obj) {// statements 2 }锁粗化后代码: synchronized (obj)…

pycharm绘图时中英文不能同时出现 中文出现小框框的问题解决

# 设置字体为微软雅黑,正确显示负号 plt.rcParams[font.sans-serif] [Microsoft YaHei] plt.rcParams[axes.unicode_minus] False

Python 组合序号

import pandas as pd # 创建一个示例数据框 data { group: [A, A, A, B, B, C, C, C, C], value: [3, 1, 2, 5, 4, 6, 9, 7, 8] } df pd.DataFrame(data) # 先按group分组,再按value列升序排序 df_sorted_asc df.sort_values(by[group, value]) # 使…

如何使用vsCode打开intel D435i深度相机

一、下载并安装相机SDK文件 1.SDK下载地址: Release Intel RealSense™ SDK 2.0 (v2.54.2) IntelRealSense/librealsense GitHub 2.下载后,双击即可安装 3.环境配置 1)window的开始菜单,搜索环境变量,选择编辑系…

LitCTF2024部分wp

litctf wp 第一次ak了web和misc,非常激动,感谢lictf给我这个机会 最终成果 全靠队里的密码逆向✌带飞。一个人就砍了近一半的分数 这里是我们队的wp web exx 题目名反过来就是xxe,考察xxe,查看登录的数据包 发现传的就是xml…

机器学习中的泛化与适应:深入理解域泛化、域适应、少样本学习、零样本学习、开放世界识别与开放词汇识别

机器学习中的泛化与适应:深入理解域泛化、域适应、少样本学习、零样本学习、开放世界识别与开放词汇识别 😎 作者介绍:我是程序员行者孙,一个热爱分享技术的制能工人。计算机本硕,人工制能研究生。公众号:A…

Java Web学习笔记8——表单

表单标签&#xff1a; 场景&#xff1a;在网页中主要负责数据采集功能&#xff0c;如注册、登录等数据采集。 标签&#xff1a;<form> 表单项、表单元素&#xff1a; 不同类型的input元素、下拉列表、文本域等。 <input>: 定义表单项、通过type形式控制输入形…

echarts系列:echarts中的legend名称最上面被遮挡一部分

在 ECharts 中,遇到 legend 的名称在图表中被遮挡。 被遮挡的原因,通常是因为布局问题,可能涉及到 legend 的位置、尺寸或者是与其他组件的重叠。 通过排查问题,发现以下一些解决 legend 名称被遮挡的方案: 调整 Legend 的位置: 你可以通过改变 legend 的 top, bottom, …

深入解读Prometheus Adapter:云原生监控的核心组件

一、引言 Prometheus Adapter的背景与重要性 在现代的云原生架构中&#xff0c;微服务和容器化技术得到了广泛的应用。这些技术带来了系统灵活性和扩展性的提升&#xff0c;但同时也增加了系统监控和管理的复杂度。Prometheus作为一款开源的监控系统&#xff0c;因其强大的指标…

JAVA面试八股文----Mybatis

1、Mybatis 1.1#{}和${}的区别是什么? Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值; Mybatis在处理 0 时,就是把 0时,就是把 0时,就是把{}替换成变量的值。 有了#{}为什么还需要${}? #{}会被预编译处理,可以有效的防止SQL注…

有关Qt的调用其他cpp文件出现的小问题

一开始出现了运行mainwindow文件过程调用其他cpp文件&#xff0c;而导致运行的ui界面卡住&#xff0c;后来发现在两个cpp文件中都进行了界面的初始化而导致界面的某些控件二次使用&#xff0c;所以会卡住。 ui->setupUi(this); 在Qt框架中&#xff0c;ui->setupUi(this)…

PPP-B2b精密产品使用注意事项及分析

1、因为在使用PPP-B2b进行定轨的时候&#xff0c;发的精密轨道产品是B3频点的&#xff0c;需要改正的卫星质心&#xff08;Com&#xff09;与SP3精密星历对比。 2、PPP-B2b产品吸收了电离层误差&#xff0c;因此电离层提取方面与IGS电离层完全无法对其。 3、由于PPP-B2b产品精…

JS包装类:为什么循环中为什么建议用变量存储str.length进行循环判断?

前言 在Javascript通常我们在遍历一个字符串的时候通常使用的方式是 var str "abcdefg"; for(let i0;i<str.length;i){}但在最近的学习中&#xff0c;有人建议我最好应该是下面这样执行。 var str "abcdefg"; for(let i0,len str.length;i<len;i)…

元宇宙3D品牌营销虚拟场景提升客户对企业的黏性

在这个充满创意与想象的3D元宇宙时代&#xff0c;我们为您推出了全新的3D元宇宙场景在线制作编辑平台&#xff0c;让您轻松构建专属的虚拟展厅&#xff0c;展现无限可能。 3D元宇宙场景在线制作编辑平台允许您快速完成空间设计&#xff0c;根据您的个性化需求&#xff0c;自由设…

适合初学者人手一本的LLM大语言模型综述,爆火全网

今天给大家推荐一本大模型&#xff08;LLM&#xff09;这块的一本外文书&#xff0c;经过整理已经出中文版了&#xff0c;就是这本《大型语言模型综述》&#xff01;本书在git上有9.2k star&#xff0c;还是很不错的一本大模型方面的书。 本教程内容主要内容&#xff1a;中文版…

python cs socket通信

#server import socket import threading import json import select def send_data(client,addr): while(1): ssinput(f"要发送给{addr}输入&#xff1a;") client.send(ss.encode("utf-8")) pass def recv_data(client,add…

牛客热题:矩阵最长递增路径

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;力扣刷题日记 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 文章目录 牛客热题&#xff1a;矩阵最长递增路径题目链接方法一…

leetcode155 最小栈

题目 设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。void push(int val) 将元素val推入堆栈。void pop() 删除堆栈顶部的元素。int top() 获取堆栈顶部的元素。i…