一次项目代码重构-使用spring容器干掉条件判断
一次项目代码重构-使用spring容器干掉条件判断
这是在一次公司项目中进行重构时,一些复杂业务时想到的一个去掉一些if else的办法。能够使代码逻辑更加清晰,减少一些业务上的耦合。
业务说明
我所在的是一个做保险的项目组,这次重构是针对其中的保费计算和核保的业务。
项目重构之前,在保费计算的接口中,有大量的条件判断语句来判断这次进行保费计算的产品是哪一个,然后调用该产品的保费计算方法。代码大致看起来就是这个样子:
//产品编号
String product = "123123";
if (product.equals("11111")) {
} else if (product.equals("11111")) {
//使用产品编号是11111的service类进行保费计算
//
} else if (product.equals("22222")) {
//使用产品编号是22222的service类进行保费计算
//
} else {
//执行其他的保费计算
}
这些通过一个编号进行判断并执行特定代码的方法在项目中到处都是,一旦添加了新的产品,或者产品在一些特定销售渠道中有特定的一些操作(比如有一些折扣啊什么的)就要在代码的各种关键地方添加一堆 if eles,大大影响了代码的可读性和可维护性。常常是修改了一处代码,影响到很多别的地方,造成一些看起来很奇怪的bug。
所以我在接手这个项目的时候想到了重构。希望在重构后能够使各个产品之间的代码没有关联,业务分明,相互不影响。
开始重构
分析业务,抽象出接口
重构代码之前要先分析一下业务,因为我的这个项目是做保费计算的,虽然有一大堆的判断产品编号的代码,但是最终它们做的都是同一件事情。这里可以把保费计算抽象成为一个接口,在接口中定义执行保费计算所需要的共同的方法。大致上是这个样子:
/**
* 保费计算接口
*
* @author hjx
*/
public interface PremiumCalculate {
//保费计算
Result calculate(Param param);
//其他的保费计算中需要的方法
。。。
}
这一步主要是梳理一下项目中的业务,并把业务中相同的步骤抽象出来。
根据不同的产品实现不同产品的保费计算
这一步就是实现上面的接口了,每个产品实现一遍接口。这里会存在一个问题,就是有很多产品在进行保费计算的时候,只有某几个步骤不一样。如果每个实现上都写一遍,会造成大量的重复代码。
我们可以建一个抽象类来实现这个接口,将大部分共有的实现代码写在抽象类中。就像这样:
/**
* 抽象的保费计算
*/
public abstract class AbstractPremiumCalculate implements PremiumCalculate {
/**
* 实现共有的一些代码
* @param premiumInfo
* @return
*/
@Override
public Result calculate(Param param) {
//将共有的实现写在这里
}
}
这样在新添加一个实现类的时候只要继承这个抽象类,重写其中的某些方法就可以了。这时我们可能有很多实现类,比如:
PremiumCalculateP001Impl.java
PremiumCalculateP002Impl.java
PremiumCalculateP003Impl.java
PremiumCalculateP004Impl.java
这时就可以在执行保费计算的时候根据不同的产品调用不同的实现。每个实现类只写一个产品的业务就行,类之间相互不影响。在新添加产品的时候也是只需要添加一个新的实现类就好了。
但是这样还有问题
但是这样还是有问题的,因为还是要在业务代码中写一堆的if else 来判断这次到底需要哪一个实现类来执行保费计算,这时可以写一个工厂类。根据传入的产品编号或者别的什么参数,返回特定的一个实现类,像是这样:
/**
* 保费计算接口工厂类
*/
@Service
public class PremiumCalculateFactory {
@Autowired
@Qualifier("premiumCalculateP0001")
private PremiumCalculate premiumCalculateP0001;
@Autowired
@Qualifier("premiumCalculateP0002")
private PremiumCalculate premiumCalculateP0002;
@Autowired
@Qualifier("premiumCalculateP0003")
private PremiumCalculate premiumCalculateP0003;
@Autowired
@Qualifier("premiumCalculateP0004")
private PremiumCalculate premiumCalculateP0004;
。。。。其他的保费计算实现对象
public PremiumCalculate getPremiumCalculate(String productCode) {
if (productCode.equals("P0001")) {
return premiumCalculateP0001;
} else if () {
//其他的条件下,返回其他的对象
}
}
}
添加了工厂类之后,我们在获取保费计算对象的时候只需要调用getPremiumCalculate()方法就可以了,具体返回哪一个实现对象,就交给工厂类来处理。可以精简调用保费计算时的代码。
还是免不了写if else,改造PremiumCalculateFactory
在提供了工厂类之后,还是免不了写很多的条件判断,只不过是把所有的条件判断写在了一起。这时随着产品数量的增多,if else 也会不停地增多,维护起来依然费劲。
这里spring容器就可以排上用场了。spring中有一个BeanFactory对象,也是一个工厂,我们可以用它来改造PremiumCalculateFactory。
首先我们在编写各个产品对应的保费计算实现类的时候都会将它注册进spring容器中,成为一个bean。我们需要给这个bean指定一个名称比如:
//在这里指定bean的名称
@Service("PremiumCalculate:"+产品编号)
public class PremiumCalculateP0001Impl implements PremiumCalculate {
。。。
}
然后修改PremiumCalculateFactory
/**
* 保费计算接口工厂类
*/
@Service
public class PremiumCalculateFactory {
@Autowired
private BeanFactory beanFactory;
public PremiumCalculate getPremiumCalculate(String productCode) {
Object bean = beanFactory.getBean("PremiumCalculate:" + productCode);
if (bean instanceof PremiumCalculate) {
return (PremiumCalculate) bean;
}
throw new UnsupportedOperationException("不支持的编号:" + productCode);
}
}
这样,条件判断的步骤就可以省略了。
结果
在保费计算和核保项目经过这样重构后,每个产品的业务代码相互不关联,维护和添加产品时也能减少工作量,还是比较成功的。
不足
这样写会有一个比较大的问题,就是在产品数量增多的时候,java文件数量也会随之变多。但是目前的业务中产品数量还可以忍受。由于产品配置功能的出现,大部分产品都可以通过数据库配置出来。这里只是写配不出来的一部分,所以这种模式还是可行的。
没了
https://www.cnblogs.com/hebaibai/p/11095590.html
一次项目代码重构-使用spring容器干掉条件判断的更多相关文章
- 使用spring容器干掉if-else
spring容器干掉if-else 场景说明 最近新做一个项目,需要对不同店铺的商品做不同处理.例如storeA需要进行handleA操作,storeB需要进行handleB操作,如此类推 大家很容易 ...
- spring容器干掉if-else
场景说明 最近新做一个项目,需要对不同店铺的商品做不同处理.例如storeA需要进行handleA操作,storeB需要进行handleB操作,如此类推 大家很容易会想到下面的实现方法 public ...
- 重构指南 - 使用多态代替条件判断(Replace conditional with Polymorphism)
多态(polymorphism)是面向对象的重要特性,简单可理解为:一个接口,多种实现. 当你的代码中存在通过不同的类型执行不同的操作,包含大量if else或者switch语句时,就可以考虑进行重构 ...
- springMVC项目部署 服务器启动spring容器报错bean未从类加载器中找到
bean未从类加载器中找到 警告: Exception encountered during context initialization - cancelling refresh attempt: ...
- Spring配置文件中条件判断标签
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.Prop ...
- 项目中spring容器加载的问题
今天做一个项目采用的是传统架构,没有采用分布式,部署时出现了异常,信息是: org.springframework.beans.factory.NoSuchBeanDefinitionExceptio ...
- spring容器初始化执行某个方法
在做web项目开发中,尤其是企业级应用开发的时候,往往会在工程启动的时候做许多的前置检查. 比如检查是否使用了我们组禁止使用的Mysql的group_concat函数,如果使用了项目就不能启动,并指出 ...
- 当spring 容器初始化完成后执行某个方法
在做web项目开发中,尤其是企业级应用开发的时候,往往会在工程启动的时候做许多的前置检查. 比如检查是否使用了我们组禁止使用的Mysql的group_concat函数,如果使用了项目就不能启动,并指出 ...
- spring 容器加载完成后执行某个方法
理论 刚好再开发过程中遇到了要在项目启动后自动开启某个服务,由于使用了spring,我在使用了spring的listener,它有onApplicationEvent()方法,在Spring容器将所有 ...
随机推荐
- cordova打包之android应用签名
原文:cordova打包之android应用签名 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/mate_ge/article/details/78 ...
- Web 程序的建立
1 导读 web 基础研发体系指的是, web 研发中一线工程师所直接操作的技术.工具,以及所属组织架构的总和.在过去提升企业研发效能的讨论中,围绕的主题基本都是——”通过云计算.云存储等方式将底层核 ...
- 科学的解决Http Token拦截器TokenInterceptor实现
1.写在前面 在做项目的时候,有时对接口要求比较严谨.先介绍下情况. 我这边Http 方式采用的是 OKhttp+Retrofit 后台一共分为三种token,分别是实名token(accessTok ...
- Android 项目框架功能整理记录
用来记录自己在项目用到的框架工具等,新人新记录,希望能对你搭建项目有所帮助 常用框架整理 视图绑定注解框架: butterKnife 网络请求框架: OKHttp 图片加载缓存:Gilde 数据格式解 ...
- BS学习概述
从最初的牛腩新闻公布系统,到如今的JS,回想一下,自己的BS也算是学了大半,可是有时候想起来还是总是有一种不踏实的感觉,一是由于从开学到如今赶上了三级考试,自考.软考,导致BS学习时间被大大压缩了,代 ...
- WPF 路由事件 Event Routing
原文:WPF 路由事件 Event Routing 1.路由事件介绍 之前介绍了WPF的新的依赖属性系统,本篇将介绍更高级的路由事件,替换了之前的.net普通事件.相比.net的事件,路由事件具有更强 ...
- 大约PCA算法学习总结
文章来源:http://blog.csdn.net/xizhibei ============================= PCA,也就是说,PrincipalComponents Analys ...
- WPF实现选项卡效果(1)——使用AvalonDock
原文:WPF实现选项卡效果(1)--使用AvalonDock 简介 公司最近一个项目,软件采用WPF开发,需要实现类似于VS的选项卡(或者是浏览器的选项卡)效果.搜寻诸多资料后,发现很多同仁推荐Ava ...
- MVC 用基架创建Controller,通过数据库初始化器生成并播种数据库
1 创建MVC应用程序 2 在Model里面创建实体类 using System; using System.Collections.Generic; using System.Linq; using ...
- 日志文件 清理or压缩
1.操作前请断开所有数据库连接. 2.分离数据库 分离数据库:企业管理器->服务器->数据库->cwbase1->右键->分离数据库 分离后,cwbase1数据库被删除, ...