1. 前言
我相信很多在刚刚使用Spring的同事会考虑一个问题:
我们为什么要用Spring,Spring虽然给我们带来了一些好处,可是,似乎好处似乎不是那么明显。IOC的作用似乎也很牵强。
所以,冷凝沙漠在此记录了自己的一些Spring开发经验,与各位分享。
2. 一个常见的业务场景
2.1. 场景简介
一个非常常见的业务场景是:程序中会根据某一个特殊的参数,定义一系列不同的执行方式。
流程如下图所示:
2.2. 代码示例
形成代码之后大概会这么写:
publicclass Example1 { publicstaticvoid main(String[] args) { String specialParam = args[0];// 这是一个特定的参数
Object[] param1 = new Object[] {}; Object[] param2 = new Object[] {}; Object[] param3 = new Object[] {}; // ………… 以上是一堆常见、有规则的其他参数
if ("CanShu1".equals(specialParam)) {
// ………… 一堆冗长的程序
} elseif ("CanShu2".equals(specialParam)) { // ………… 又一堆冗长的程序
} elseif ("CanShu3".equals(specialParam)) {
// ………… 再一堆冗长的程序
} else {
// ………… 其他默认的冗长的程序 } } } |
2.3. 优缺点分析
从这个示例的角度,代码挺清晰的,但是到了实际应用中,可能就会有数十套逻辑,可能会有长达数千行代码,可能会绕晕很多人。
3. 一个常见的不好的修改方式
3.1. 场景简介与代码示例
如下是很常见的一个修改方式,将不同的流程提炼出独立的方法,让逻辑判断的位置独立出来。
publicclass Example2 {
publicstaticvoid main(String[] args) { String specialParam = args[0];// 这是一个特定的参数
Object[] param1 = new Object[] {}; Object[] param2 = new Object[] {}; Object[] param3 = new Object[] {}; // ………… 以上是一堆常见、有规则的其他参数
// 提炼独立方法 if ("CanShu1".equals(specialParam)) { handleCanShu1(param1, param2, param3); } elseif ("CanShu2".equals(specialParam)) { handleCanShu2(param1, param2, param3); } elseif ("CanShu3".equals(specialParam)) { handleCanShu3(param1, param2, param3); } else { handleDefault(param1, param2, param3); } }
publicstaticvoid handleCanShu1(Object[] param1, Object[] param2, Object[] param3) { // ………… 一堆冗长的程序 }
publicstaticvoid handleCanShu2(Object[] param1, Object[] param2, Object[] param3) { // ………… 又一堆冗长的程序 }
publicstaticvoid handleCanShu3(Object[] param1, Object[] param2, Object[] param3) { // ………… 再一堆冗长的程序 }
publicstaticvoid handleDefault(Object[] param1, Object[] param2, Object[] param3) { // ………… 其他默认的冗长的程序 } } |
3.2. 优缺点分析
相信各位维护的旧项目里面不会缺乏此类代码。
从维护的角度来看:
1. 如果要继续更新这个代码,也只能不断的在这个类上下功夫。很可能这个类未来会变成一个“只有上帝知道它是干嘛的”的复杂类。
2. 必须要有源码才能更新代码,才能重新编译。相信我,很多维护方没有源代码,这种修改对于程序员而言属于“Mission Impossible”。当然,对于搞IT的,天天玩程序员版的碟中谍,也是家常便饭。
因此,大部分Java培训师、Team Leader、代码走查员都会说:这样不好,这样不好!
4. 中规中矩的工厂模式
4.1. 场景简介
从模式的角度来看,工厂模式自然是这里最适合的模式:
咱们先提炼一个公共的接口,定义一个调用的工厂,再不断实现这个接口,并将接口注册到工厂。
未来如果要增加一种业务,就单独增加一个实现类,并注册到工厂就行了。
4.2. 代码示例
以下是一套简单的实现代码:
publicclass Example3 { publicstaticvoid main(String[] args) { String specialParam = args[0];// 这是一个特定的参数
Object[] param1 = new Object[] {}; Object[] param2 = new Object[] {}; Object[] param3 = new Object[] {}; // ………… 以上是一堆常见、有规则的其他参数 Example3Service service = Example3Factory.getService(specialParam); service.run(param1, param2, param3);
} } |
调用其实是很简单的。
package com.test; /** * 提炼出工厂和接口 */ publicclass Example3Factory { publicstatic Example3Service getService(String specialParam) { if ("CanShu1".equals(specialParam)) { returnnew Example3ServiceCanShu1Impl(); } elseif ("CanShu2".equals(specialParam)) { returnnew Example3ServiceCanShu2Impl(); } elseif ("CanShu3".equals(specialParam)) { returnnew Example3ServiceCanShu3Impl(); } else { returnnew Example3ServiceDefaultImpl(); } } } |
工厂类可以简单的如例子中写死,也可以写成collection形式,然后进行注册。
package com.test; /** * 提炼出工厂和接口 */ publicinterface Example3Service { publicvoid run(Object[] param1, Object[] param2, Object[] param3); }
|
接口神马的最简单了,以下就是接口实现:
package com.test;
publicclass Example3ServiceCanShu1Impl implements Example3Service { publicvoid run(Object[] param1, Object[] param2, Object[] param3) { // ………… 一堆冗长的程序 } } |
package com.test;
publicclass Example3ServiceCanShu2Impl implements Example3Service { publicvoid run(Object[] param1, Object[] param2, Object[] param3) { // ………… 又一堆冗长的程序 } } |
package com.test;
publicclass Example3ServiceCanShu3Impl implements Example3Service { publicvoid run(Object[] param1, Object[] param2, Object[] param3) { // ………… 再一堆冗长的程序 } } |
package com.test;
publicclass Example3ServiceDefaultImpl implements Example3Service { publicvoid run(Object[] param1, Object[] param2, Object[] param3) { // ………… 其他默认的冗长的程序 } } |
4.3. 优点分析
形成工厂模式的优点很明显:
l 提供创建对象的接口. 为系统结构提供了非常灵活强大的动态扩展机制,只要我们更换一下具体的工厂方法,系统其他地方无需一点变换,就有可能将系统功能进行改头换面的变化。
l 除了工厂类以外的程序都不需要去了解具体的实现情况,所以给程序实现带来了很多方便。
l 将程序的一部分复杂度集中在接口的实现上,一部分程序员可以专心于如何通过实现接口来实现业务逻辑,另一部分程序员可以专心于通过更新工厂注册方式来将新的实现对接到整个程序中。
4.4. 缺点分析
形成工厂模式的缺点也很明显:
l 工厂类依旧需要去了解具体的实现类以及其参数,当程序复杂度到一定程度时,工厂类依旧可能很复杂。
l 还是必须要有源码才能更新工厂类的代码,才能重新编译。
5. 开始引入Spring
5.1. 场景简介
既然工厂模式的缺点集中在工厂上,那么就优化工厂好了。我们可以把工厂优化为抽象厂,也可拆掉这个工厂,用Spring来替代这个工厂。
可以这样想,工厂类就是提供了一个Map,根据一个特定的key值,找一个特定的Bean。如果仅仅是这样,Spring自身是不是就能作为这个工厂了?
5.2. 代码示例
调用方的代码依旧很简单:
package com.test; import java.util.Map; import javax.annotation.Resource; publicclass Example4 { @Resource private Map example4ServiceMap; @Resource private Example4Service example4ServiceDefaultImpl;
publicvoid runMain(String specialParam) { Object[] param1 = new Object[] {}; Object[] param2 = new Object[] {}; Object[] param3 = new Object[] {}; // ………… 以上是一堆常见、有规则的其他参数
Example4Service service = example4ServiceMap.get(specialParam); if (service == null) { service = example4ServiceDefaultImpl; } service.run(param1, param2, param3); } } |
工厂的内容直接用Spring配置完成:
xmlversion="1.0"encoding="UTF-8"?> <<>beansxmlns=http://www.springframework.org/schema/beans ……………… xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd …………">
<<>beanid="example4ServiceMap" class="java.util.HashMap"> <<>constructor-arg> <<>map> <<>entrykey="CanShu1"value-ref="example4ServiceCanShu1Impl"/> <<>entrykey="CanShu2"value-ref="example4ServiceCanShu2Impl"/> <<>entrykey="CanShu3"value-ref="example4ServiceCanShu3Impl"/> <map> <constructor-arg> <bean>
<beans> |
接口以及其实现类没有啥变化,只是多了些注解而已。当然,需要好好管理Spring中的Bean:
package com.test; /** * 提炼出工厂和接口 */ publicinterface Example4Service { publicvoid run(Object[] param1, Object[] param2, Object[] param3); } |
实现这里就只多了个注解:
package com.test; import org.springframework.stereotype.Service;
@Service publicclass Example4ServiceCanShu1Impl implements Example4Service { publicvoid run(Object[] param1, Object[] param2, Object[] param3) { // ………… 一堆冗长的程序 } } |
package com.test;
import org.springframework.stereotype.Service;
@Service publicclass Example4ServiceCanShu2Impl implements Example4Service { publicvoid run(Object[] param1, Object[] param2, Object[] param3) { // ………… 又一堆冗长的程序 } } |
package com.test;
import org.springframework.stereotype.Service;
@Service publicclass Example4ServiceCanShu3Impl implements Example4Service { publicvoid run(Object[] param1, Object[] param2, Object[] param3) { // ………… 再一堆冗长的程序 } } |
package com.test;
import org.springframework.stereotype.Service;
@Service publicclass Example4ServiceDefaultImpl implements Example4Service { publicvoid run(Object[] param1, Object[] param2, Object[] param3) { // ………… 其他默认的冗长的程序 } } |
5.3. 优缺点分析
这个方法的优点在于,不需要代码书写工厂类了,只是一个简单的XML配置文件,就搞定了,因此,将新类注册到整个程序时,也就不需要源码、编译之类的,如果没有特殊情况,只要编译实现类就行了。
6. 进一步简单化
6.1. 场景简介
那能不能更简单一些呢?
能!
6.2. 代码示例
调用方的稍微调整一下,会更简单:
package com.test;
importjava.util.Map;
import javax.annotation.Resource;
import……………….SpringUtil;
publicclass Example5 {
@Resource private Example5Service example5ServiceDefaultImpl;
publicvoid runMain(String specialParam) { Object[] param1 = new Object[] {}; Object[] param2 = new Object[] {}; Object[] param3 = new Object[] {}; // ………… 以上是一堆常见、有规则的其他参数
Example5Service service = (Example5Service) SpringUtil.getBean("example5Service" + specialParam + "Impl"); if (service == null) { service = example5ServiceDefaultImpl; } service.run(param1, param2, param3); } } |
仅仅是将调用方式微调一下,配置文件也就不需要了。
而接口和实现类则不会受到影响,不再重复粘贴了。
这里的SpringUtil在各个公司应该都有自己的简单实现,就不自己费力写了。
当然,事务之类的周边事宜还是需要各位自己在配置文件中好好管理起来的。
6.3. 优缺点分析
到这个时候,程序已经初步从配置变成了流行的“规则”了。运维人员需要增加一个新业务时,只是需要保证类名保持一定的规则,而且Bean name在管理范围内,没有啥冲突,就行了。
7. 后语
在此,冷凝沙漠只是记录了一个初步的思路来给大家启发大家思路。真正在程序开发的过程中需要比这更加细腻的设计过程。
希望这篇博文能解决大家在工作中遇到的问题。
本文链接:Spring与工厂模式,原作者:冷凝沙漠,转载必须注明出处和作者
相关推荐
使用spring编写的工厂模式,来实现控制反转,并且面向切面编程。
实现spring底层原理。 例如spring是如何创建bean的等等。
本项目为Java项目,使用Spring实现控制反转,对比简单工厂模式实现,适合初学者了解控制反转实现。
第四章:Spring AOP 设计模式小马哥(mercyblitz)Spring AOP 设计模式抽象工厂模式(Abstract factory)实现构建器模式
Spring02_工厂模式与Spring入门.zip
本资源是spring的小例子程序,共包括以下7...工厂模式(factory) 模型视图控制器模式(MVC) 代理模式(proxy) 单例模式(singleton) 策略模式(strategy) 模板模式(template) 另外还有一个关于动态代理的小例子
作为一个资深Java工程师,我发现《Spring 设计模式总结》PDF非常精彩,它深入剖析了Spring框架中的关键设计模式。例如,简单工厂模式通过BeanFactory展现,实现了松耦合和动态对象创建。工厂方法模式则通过...
主要介绍了如何基于Spring使用工厂模式实现程序解耦,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
Spring设计模式简介:主要是讲述Spring源码中运用到的一些设计模式 Ibatis设计模式简介:主要是讲述Ibatis源码中运用到的一些设计模式 设计模式简介 1 单例模式 2 责任链模式 3 策略模式 4 模板方法模式 5 工厂方法...
工厂模式几种类型的测试,并有spring ioc 的简单实现!
Spring设计思想 Spring实现了两种基本设计模式工厂模式 单态模式
——Lasse Koskela.JavaRanch版主,Test Driven作者“《深入解析Spring MVCgn Web Flow》是非常急缺的深入讲解Spring MVCf~~Spring Web Flow的图书堪与Pro Spring相媲美。” ——Steve Anglin,资深Java技术专家
spring的设计思想是,单例模式和工厂模式 2 spring的四大特点(优点) 轻量级,低侵入的设计 Spring的DI机制降低了业务对象替换的复杂性 spring不依赖于web容器,独立于各种应用服务器, Write Once,Run Anywhere...
提供Spring框架的基本功能,其主要组件是BeanFactory,是工厂模式的实现。 Spring 上下文。向Spring 框架提供上下文信息,包括企业服务,如 JNDI、EJB、电子邮件、国际化、校验和调度等。 Spring AOP。通过配置管理...
设计模式-工厂模式 学习练习的代码 1.简单工厂模式 2.方法工厂模式 3.抽象工厂模式 4.模拟Spring Bean工厂练习
重构第三步——工厂(Factory)模式的改进 10 重构第四步-IoC容器 11 控制反转(IoC)/依赖注入(DI) 11 什么是控制反转/依赖注入? 11 依赖注入的三种实现形式 12 BeanFactory 14 BeanFactory管理Bean...
Java简单工厂模式和传统模式实现对比,通过简单实例比对两种方式差异,体现传统模式的弊端及工厂模式优势。利于初学者后续接触spring
spring-2 演示了外部配置文件的引入(connection),spel(spring el)表达式 ,静态工厂方式及实例工厂方式及factorybean方式创建bean, spring的生命周期及BeanPostProcessor的使用,注解方式创建bean 及使用...
重构第三步——工厂(Factory)模式的改进 10 重构第四步-IoC容器 11 控制反转(IoC)/依赖注入(DI) 11 什么是控制反转/依赖注入? 11 依赖注入的三种实现形式 12 BeanFactory 14 BeanFactory管理Bean(组件)的...
javaEE 开发中 现在最成熟的框架之一应该就是spring了 spring框架最强大的地方就是实现了依赖注入 也叫控制反转 最近的一个项目中用的就是 spring框架 spring框架是工厂模式的应用结合了MVC的设计思想 大家可以...