如何在Spring中巧妙应用工厂模式实现解耦

一、工厂模式

工厂模式通过定义一个用于创建对象的接口,让子类决定实例化哪一个类。该模式的目的是使系统在不明确指定对象具体类型的情况下,通过调用工厂方法来创建对象。在Java中,工厂模式可以帮助我们封装对象的创建逻辑,使得代码更加灵活和可扩展。

二、工厂模式在Spring中的体现

在Spring中,工厂模式常通过BeanFactory或FactoryBean来实现,它们提供了创建Bean的灵活方式并进一步解耦了代码。

1. BeanFactory和FactoryBean的概念区分

BeanFactory

BeanFactory是Spring IoC容器的根接口,它定义了Spring容器获取Bean的各种方法。通常情况下,我们通过ApplicationContext来使用IoC容器,而ApplicationContext是BeanFactory的子接口,提供了更多的企业级功能。

FactoryBean

FactoryBean是一个接口,当在Spring应用上下文中配置一个FactoryBean,它将产生一个由该FactoryBean定义创建的Bean。与直接实例化Bean不同,FactoryBean为Spring提供了一种插件式的方式来创建特定的Bean,更加灵活。

2. 使用工厂模式创建Bean的步骤和配置

要使用Spring中的工厂模式来创建Bean,可以通过实现FactoryBean接口,下面是一个简单的例子:

import org.springframework.beans.factory.FactoryBean;
import com.example.SomeService;public class MyServiceFactoryBean implements FactoryBean<SomeService> {private String someParameter;@Overridepublic SomeService getObject() throws Exception {return new SomeService(someParameter);}@Overridepublic Class<?> getObjectType() {return SomeService.class;}// setter for someParameter
}

配置MyServiceFactoryBean到Spring上下文:

<bean id="myService" class="com.example.MyServiceFactoryBean"><property name="someParameter" value="myValue"/>
</bean>

或使用Java配置:

@Configuration
public class AppConfig {@Beanpublic FactoryBean<SomeService> myService() {MyServiceFactoryBean factory = new MyServiceFactoryBean();factory.setSomeParameter("myValue");return factory;}
}

使用FactoryBean可以让创建SomeService的逻辑抽象化,这样你就可以在不同的场景给出不同的实现。

三、实现工厂模式的几种方法

在Spring框架中,我们可以通过许多方法来实现工厂模式。以下我们将会探讨两种常见的方法:静态工厂方法和实例工厂方法。

1. 静态工厂方法实现

静态工厂方法是一种通过调用一个静态方法来返回实例的方法。在Spring中,你可以使用的factory-method属性来指定工厂方法的名称。
下面是一个静态工厂方法的示例:

public class MyServiceFactory {public static SomeService createService(String someParameter) {return new SomeService(someParameter);}
}

在Spring配置文件中配置使用这个静态工厂方法:

<bean id="myService" class="com.example.MyServiceFactory" factory-method="createService"><constructor-arg value="myValue"/>
</bean>

在这个例子中,当Spring容器需要创建myService Bean时,它会调用MyServiceFactory类的createService静态方法。

2. 实例工厂方法实现

与静态工厂方法相比,实例工厂方法需要先创建工厂本身的实例。以下是一个实例工厂方法的实现:

public class MyServiceInstanceFactory {private String someParameter;public MyServiceInstanceFactory(String someParameter) {this.someParameter = someParameter;}public SomeService createService() {return new SomeService(someParameter);}
}

在Spring配置中创建工厂实例并指定工厂方法:

<bean id="myServiceFactory" class="com.example.MyServiceInstanceFactory"><constructor-arg value="myValue"/>
</bean><bean id="myService" factory-bean="myServiceFactory" factory-method="createService"/>

在这个例子中,MyServiceInstanceFactory类的实例会首先被创建,然后Spring容器会调用其createService方法来生产SomeService的实例。

四、案例分析——工厂模式解耦实战

为了具体展示工厂模式在Spring中的实际应用,让我们通过一个常见的场景来进行分析:不同类型的消息处理。在此场景中,我们将设计一个系统,需要根据不同类型的消息来进行不同的处理。

1. 情境描述:不同类型消息处理

假设我们有一个应用,它需要处理多种类型的消息,如SMS、Email和Push通知。如果我们直接在代码中硬编码所有的类型和处理逻辑,每当添加新类型时就需要修改代码,并且处理器之间会高度耦合,这明显违反了开闭原则(对扩展开放,对修改封闭)。

2. 工厂模式应用解决方案

通过工厂模式,我们可以定义一个公共的接口MessageHandler,以及多个实现类,每个实现类处理一种类型的消息。同时,我们建立一个MessageHandlerFactory来封装消息处理器的创建逻辑。

public interface MessageHandler {void handleMessage(Message msg);
}public class SmsMessageHandler implements MessageHandler {public void handleMessage(Message msg) {// SMS处理逻辑}
}public class EmailMessageHandler implements MessageHandler {public void handleMessage(Message msg) {// Email处理逻辑}
}

工厂类:

public class MessageHandlerFactory {public static MessageHandler getMessageHandler(String messageType) {switch (messageType) {case "SMS":return new SmsMessageHandler();case "EMAIL":return new EmailMessageHandler();// 可扩展更多处理器default:throw new IllegalArgumentException("Unknown message type: " + messageType);}}
}

3. 代码实现与解释

现在,当应用接到一个新消息时,只需要调用MessageHandlerFactory来获取对应的处理器,并委托给该处理器来处理消息:

MessageHandler handler = MessageHandlerFactory.getMessageHandler(messageType);
handler.handleMessage(msg);

这样,我们的应用就进一步解耦了。当有新的消息类型需要处理时,我们只需添加一个对应的处理器类,并在工厂中添加相应的逻辑,而不必修改现有代码。

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

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

相关文章

【学习笔记二十一】EWM仓库两步拣配配置及操作展示

一、EWM两步拣配配置 1.定义两步拣配的WPT ①第一步:标准WPT2020,目标仓位是2010两步拣配的仓位,并创建存储类型2010的两步拣配的仓位 ②第二步,标准WPT2010,目标仓位9020发货区和发货的仓位 2.定义确定仓库处理类型的控制标识 3.确定仓库处理类型 4.仓库编码级别需要允…

Qt 集成OSG

Qt 你好 | 专注于Qt的技术分享平台 一&#xff0c;新建一个 QOsgWidget 类&#xff0c;继承自osgQOpenGLWidget #ifndef QOSGWIDGET_H #define QOSGWIDGET_H#include <QObject> #include <osgViewer/Viewer> #include <osgQOpenGL/osgQOpenGLWidget> class…

【ES】springboot集成ES

1. 去Spring官方文档确认版本兼容性 这一版的文档里没有给出springboot的版本对应&#xff0c;但我在一个博主的文章里看到的es8.0以前的官方文档中就有给出来&#xff0c;所以还需要再去寻找spring framework和springboot的对应关系&#xff1f;&#xff1f;&#xff1f; 还…

NODEjs require报错

参考十一姐文章: ReferenceError: require is not defined in ES module scope, you can use import instead-CSDN博客 import { createRequire } from module; const require createRequire(import.meta.url);

MySQL及SQL语句

SQL语句 数据库相关概念数据查询语言&#xff08;DQL&#xff09;基本查询数据类型条件查询多表查询子查询 数据操作语言&#xff08;DML&#xff09;数据定义语言&#xff08;DDL&#xff09;数据控制语言&#xff08;DCL&#xff09;MySQL数据库约束视图练习题 数据库相关概念…

如何在linux+4090显卡安装和使用Stable Diffusion

目录 前言一、配置软件环境1.启动界面2.SD功能新体验 总结 前言 Stable Diffision火得一塌糊涂&#xff0c;作为开源阵营里文生图的典型代表&#xff0c;是跟闭源的Dall-E&#xff0c;midjourney分庭抗礼的利器。不体验一把&#xff0c;怎么能说自己是搞生成模型的呢&#xff…

基于K-means和FCM算法的合成纹理图像及SAR图像的分割

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

WPF4 数据模板

数据模板 数据模板常用在3种类型的控件, 下图形式: 1.Grid这种列表表格中修改Cell的数据格式, CellTemplate可以修改单元格的展示数据的方式。 2.针对列表类型的控件, 例如树形控件&#xff0c;下拉列表&#xff0c;列表控件, 可以修改其中的ItemTemplate。 3.修改ContentT…

Python读取influxDB数据库(二)(influxDB2.X版本)

1. influxDB连接 首先在浏览器中输入influxDB的IP和端口&#xff0c;然后输入账号密码进入到influxDB数据库来进行数据的相关操作&#xff1a; 里面的bucket相当于sql中的数据库&#xff0c;_measurement相当于sql中的表 2. 获取influxDB数据库的token方法 3. 写查询语句来查询…

【C++学习】STL之空间配置器之一级空间配置器

文章目录 &#x1f4ca;什么是空间配置器✈STL 提供六大组件的了解&#x1f440;为什么需要空间配置器&#x1f44d;SGI-STL空间配置器实现原理&#x1f302;一级空间配置器的实现 &#x1f4ca;什么是空间配置器 空间配置器&#xff0c;顾名思义就是为各个容器高效的管理空间…

关于Developers网站的一些使用分享

Android Developers 官网使用分享 语音切换android studio 版本下载最新版本下载位置历史版本下载位置 android studio 版本和 AGP 对应关系API 和 android studio 版本和 AGP 对应关系android studio 版本android 版本API levelandroid.hardware.camera2 语音切换 Developers…

MySQL数据库-备份

数据的备份还原 导出&#xff1a;先对数据库进行备份&#xff0c;然后提取备份文件中的sql语句 导入&#xff1a; 方法一&#xff1a;创建和原始数据库同名的数据库&#xff0c;然后从备份文件中导出sql语句&#xff08;此方法不需要修改导出的sql语句&#xff09;&#xff…

C++名词解释

文章目录 1.实参与形参2.参数列表、初始化列表3.实例、方法、属性、构造器、访问器、设置器4.重写、重载、隐藏5.继承与多态原理6.三种初始化方法 1.实参与形参 实参与形参&#xff1a;调用函数时传递的是实际参数&#xff0c;被调函数里接收的是形式参数。 2.参数列表、初始化…

B. Getting Zero

这题可以使用bfs的做法&#xff0c;特记录在此。 x点到mod的操作数可以视为其最短路。于是可用宽搜从1到mod建图。 有边权为(x1)%mod 和&#xff08;2*x)%mod 两种边权。 所以每次求数x到mod的最下操作数变为到mod这个顶点的最小边数。 #include "bits/stdc.h" u…

Vue3引入高德地图js API 2.0

文章目录 前言一、地图加载1.本文准备环境2.引入库3.加载地图4.加载地图控件 二、POI搜索1.什么是poi搜索2.如何使用 三、绘制点标记与信息窗体1.场景描述2.案例3.信息窗体-链接路由跳转4.进阶-通过Marker自动触发标记点&#xff08;非鼠标手动点击&#xff09; 四、jsApi地图事…

ES6判断:当前数组对象里的所有的值是否都存在于另外一个数组里

介绍 判断当前数组里的值是否都存在于另一个数组里&#xff0c;这里需要用到ES6的 every()方法&#xff0c;及 includes()方法; every(): 用于判断数组中的每一项是否均符合条件&#xff0c;并返回一个布尔值&#xff0c;都符合返回 true&#xff0c;有一个不符合就返回 fals…

SQL-DML数据操纵语言(Oracle)

文章目录 DML数据操纵语言常见的字段属性字符型字段属性char(n)varchar2(n)/varchar(n) 数值型字段属性number([p],[s]int 日期型字段属性DATEtimestamp 如何查看字段属性增加数据INSERT快捷插入 删除数据DELETE修改数据UPDATE DML数据操纵语言 定义 是针对数据做处理&#xf…

vue-json-editor

版本&#xff1a;"vue-json-editor": "^1.4.3" &#xff08;1&#xff09;下载依赖&#xff0c;npm install vue-json-editor 或 yarn add vue-json-editor &#xff08;2&#xff09;使用 <div class"code-json-editor"><vue-json…

面试 Python 基础八股文十问十答第五期

面试 Python 基础八股文十问十答第五期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01;关注专栏后就能收到持续更新&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1&#xff09;怎样将字符串转换为小…

vscode 解决无法创建临时文件。

报错&#xff1a; Fatal error: cant create C:\Users???y\AppData\Local\Temp\ccqkCS9j.o: No such file or directory 右击此 电脑 -> 属性 打开 系统信息 -> 高级系统设置 系统属性 -> 高级 -> 环境变量 将temp 和 tmp 改为其它英文路径 只更改用户变量…