策略模式在需求重构中的实际应用
2017-09-03 12:20
483 查看
策略模式定义:定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换,使得算法可独立于使用它的客户而变化。Definea family of algorithms,encapsulate each one, andmake them interchangeable. Strategy lets the algorithmvary independently from clients that use it.
适合策略模式的情景
(1)一个类定义了多种行为,并且这些行为在这个类的方法中以多个条件语句的形式出现,那么可以使用策略模式替代在类中使用的大量条件语句。
(2)程序不希望暴露复杂的、与算法有关的数据结构,那么可以使用策略模式来封装算法。
(3)需要使用一个算法的不同变体。
实际需求情景图:
需求改造前的伪代码结构:
需求改造后的uml设计图:
重构之后的项目结构图:
重构之后的代码实现:
1、 相关算法系列 Strategy层次为客户端定义了一系列的可供重用的算法或行为。
继承有助于析取出这些算法中的公共功能。
2、 消除了客户端一些if else条件语句 :当不同的行为堆砌在一个类中时 ,
很难避免使用条件语句来选择合适的行为。
含有许多条件语句的代码通常意味着需要使用Strategy模式。
缺点:
1、客户端必须知道所有的策略类,或者交由中间类进行判断,并自行决定使用哪一个策略类。
2、并没有真正消除if else 对策略的选择,只是由客户端移除到了简单工厂
可以通过反射进一步消除if else 选择判断
3 、策略模式将造成产生很多策略类
4、无法支持策略的重叠,就是说我们同一时间只能采用一种策,针对复合策略需要加入更多的设计
适合策略模式的情景
(1)一个类定义了多种行为,并且这些行为在这个类的方法中以多个条件语句的形式出现,那么可以使用策略模式替代在类中使用的大量条件语句。
(2)程序不希望暴露复杂的、与算法有关的数据结构,那么可以使用策略模式来封装算法。
(3)需要使用一个算法的不同变体。
实际需求情景图:
需求改造前的伪代码结构:
//11:商业险 //12:交强险 //13:联合报价 if("11".equals(flag) || "13".equals(flag)) { //调用autoPriceService 报价接口,完成商业险报价 mapTemp = autoPriceService.lastYearProposalDate(order, orderTemp, "11") ... //报价结果处理 } if("12".equals(flag) || "13".equals(flag)){ //构建纳税人,投保方案流程中的相关信息 ProVehicletax proVehicletaxtemp= proVehicletaxUtil.buildProVehicletax(orderTemp); proVehicletaxtemp.setProOrder(orderTemp); orderTemp.setProVehicletax(proVehicletaxtemp); //调用autoPriceService 报价接口,完成交强险报价 mapTemp = autoPriceService.lastYearProposalDate(order, orderTemp, "12"); ... //报价结果处理 } //************该结构问题描述及改进****************** 1、三种车险报价行为判断,耦合在客户端调用中 改进:提供一个工厂方法,实现行为判断与客户端的解耦 2、采用串行的调用方式,影响联合报价效率 改进:采用策略模式设计,联合报价策略中采用并行报价方案 3、lastYearProposalDate方法内部耦合了报价请求报文生成的逻辑判断 改进:采用策略模式,在各自报价策略中,生成自身的请求报文数据
需求改造后的uml设计图:
重构之后的项目结构图:
重构之后的代码实现:
/** * @author litao * */ public interface AutoPriceStrategy { /* * 获取套餐信息 */ public void createParamForComo(ProOrder order,String flag,LastCoreInfo lastCoreInfo) ; } /**单保商业险,实现类 * 继承AutoPriceCoreServiceSpringImpl * 原因:AutoPriceInsure_11、AutoPriceInsure_12、AutoPriceInsure_13 * 三个类的业务流程中公用很多方法 * * 实现AutoPriceStrategy接口 * 原因:对外只开放createParamForComo方法 * * @author tyl * */ @Service("autoPriceInsure_11") public class AutoPriceInsure_11 extends AutoPriceCoreServiceSpringImpl implements AutoPriceStrategy { @Resource private ThreadCoreExecutor threadCoreExecutor; /* * 构造函数 */ public AutoPriceInsure_11(){ } /* * 获取上年止期及系数 * 单商业对外业务流程 * @author litao 2016/12/27 */ @Override public void createParamForComo(ProOrder orderTemp,String flag,LastCoreInfo lastCoreInfo) { //设置商业险种信息 orderTemp=autoPriceCoreSingleConveter.singleBusinessRisk(orderTemp); /* * 调用父类公共方法,获取交强险上年止期 */ getLastEndDate(orderTemp,lastCoreInfo,flag); /*add by litao 2017/7/11 * 如果有转保信息,直接返回,不设置缓存 * 商业、交强险任一投保查询码存在,则不进行缓存,直接返回 */ if(StringUtils.isNotBlank(lastCoreInfo.getCheckData().getBusQueryCode()) ||StringUtils.isNotBlank(lastCoreInfo.getCheckData().getTraQueryCode())){ return; } //设置缓存 setMemCache(orderTemp,lastCoreInfo,flag); } } /**担保交强险,实现类 * 继承AutoPriceCoreServiceSpringImpl * 原因:getLastEndDate4JQ 方法会调用B201 * * 实现AutoPriceStrategy * 原因:对外只开放createParamForComo方法 * * @author litao * */ @Service("autoPriceInsure_12") public class AutoPriceInsure_12 extends AutoPriceCoreServiceSpringImpl implements AutoPriceStrategy { @Resource private AutoPriceCoreSingleConveter autoPriceCoreSingleConveter; public AutoPriceInsure_12(){ } /* *获取上年止期及系数 * 单交强对外业务流程 * @author tyl 2016/12/27 */ @Override public void createParamForComo(ProOrder orderTemp,String flag,LastCoreInfo lastCoreInfo){ //设置单交强险种信息 orderTemp=autoPriceCoreSingleConveter.singleTrafficRisk(orderTemp); /* * 调用父类公共方法,获取交强险上年止期 */ getLastEndDate(orderTemp,lastCoreInfo,flag); /*add by litao 2017/7/11 * 如果有转保信息,直接返回,不设置缓存 * 商业、交强险任一投保查询码存在,则不进行缓存,直接返回 */ if(StringUtils.isNotBlank(lastCoreInfo.getCheckData().getBusQueryCode()) ||StringUtils.isNotBlank(lastCoreInfo.getCheckData().getTraQueryCode())){ return; } //设置缓存 setMemCache(orderTemp,lastCoreInfo,flag); } } /**联合投保实现类 * @author litao * */ @Service("autoPriceInsure_13") public class AutoPriceInsure_13 extends AutoPriceCoreServiceSpringImpl implements AutoPriceStrategy { @Resource private ThreadCoreExecutor threadCoreExecutor; /* @Resource private ICacheExtend memcachedAdapter;*/ public AutoPriceInsure_13() { } /** * 对外开放接口 * @param orderTemp 订单 * @param flag 投保类型 * @param lastCoreInfo * @author litao * 联合投保情况下 子线程交强险保费计算 * @throws Exception */ @Override public void createParamForComo(ProOrder orderTemp, String flag, LastCoreInfo lastCoreInfo){ //获取父类的属性数组,并作为参数传给线程任务,注意顺序要严格匹配 Object [] objs={this.basicService,this.controlCoreService,this.autoPriceCoreSingleConveter, this.nspB201ResultHandle,this.lastEndDateHandle,this.autoPriceCoreProposalConverter, this.checkDataConverter,this.memcachedAdapter}; //商业险子线程任务对象 获取商业险上年止期 Future<LastCoreInfo> businessFuture=threadCoreExecutor.execute(new SingleBusinessThread(orderTemp,lastCoreInfo,objs)) ; //交强险子线程任务对象 获取交强上年止期 Future<LastCoreInfo> trafficFuture=threadCoreExecutor.execute(new SingleTrafficThread(orderTemp,lastCoreInfo,objs)) ; /*旧版本的思路 2017/5/11 * 非北京上海地区 ,通过获取到的上年止期,再次调用B201接口,获取商业险系数 * 因为北京上海地区,会在获取到上年止期时,直接返回系数 */ /* * future.get方法在子线程未执行完毕时会阻塞 * 等待子线程执行完毕主线程才会继续执行 * 等待最大时间8S 超时捕获异常 */ //商业险线程结果执行完毕放入缓存 try { //商业险线程结果 LastCoreInfo busCoreInfo=businessFuture.get(6L,TimeUnit.SECONDS); //交强险执行结果 LastCoreInfo trafficCoreInfo=trafficFuture.get(6L,TimeUnit.SECONDS); //两个子线程都返回结果 if(busCoreInfo!=null&&trafficCoreInfo!=null){ /*add by litao 2017/7/11 * 如果有转保信息,直接返回,不设置缓存 * 商业、交强险任一投保查询码存在,则不进行缓存,直接返回 */ if(StringUtils.isNotBlank(lastCoreInfo.getCheckData().getBusQueryCode()) ||StringUtils.isNotBlank(lastCoreInfo.getCheckData().getTraQueryCode())){ return; } //设置缓存(此时busCoreInfo或者trafficCoreInfo对象信息应该是同一个) setMemCache(orderTemp,busCoreInfo,flag); } }catch(Exception e){ e.printStackTrace(); } } } /**自动报价工厂,获取投保方案 * @author litao * */ @Service("autoPriceFactory") public class AutoPriceFactory { @Autowired private AutoPriceStrategy autoPriceInsure_11; @Autowired private AutoPriceStrategy autoPriceInsure_12; @Autowired private AutoPriceStrategy autoPriceInsure_13; @Autowired private ICache memcachedAdapter; /* * 真正实现 */ public LastCoreInfo createParamForCombo(ProOrder order,String flag){ //车架号 String vin=order.getProVehicle().getVin(); //默认做联合投保查询一次缓存 获取缓存对象 LastCoreInfo lastCoreInfo=executeChache(order,flag,vin); //获取到缓存直接返回 if (null!=lastCoreInfo){ System.out.println("缓存模块返回对象:"+"\n"+"++++++++++++++++++"+"\n"+lastCoreInfo); return lastCoreInfo; }else { //未获取到,直接走报价流程 lastCoreInfo= executeB201(order,vin,flag); System.out.println("缓存模块返回对象:"+"\n"+"++++++++++++++++++"+"\n"+lastCoreInfo); return lastCoreInfo; } } /* * 执行B201报价接口,获取上年止期 */ private LastCoreInfo executeB201(ProOrder order,String vin,String flag){ /* * 11 单商业 * 12 单交强 * 13联合投保 * 业务类型代码 */ LastCoreInfo lastCoreInfo=new LastCoreInfo(); int businessCode = Integer.parseInt(flag); switch (businessCode) { case 11: System.out.println("======单商业无缓存,开始走报价========"); autoPriceInsure_11.createParamForComo(order, flag, lastCoreInfo); break; case 12: System.out.println("======单交强无缓存,开始走报价========"); autoPriceInsure_12.createParamForComo(order, flag, lastCoreInfo); break; case 13: System.out.println("======联合投保无缓存,开始走报价========"); autoPriceInsure_13.createParamForComo(order, flag, lastCoreInfo); break; } return lastCoreInfo; } /* * add by litao 2017/03/15 * 是否获取缓存数据,获取哪个险别的缓存数据 * */ private LastCoreInfo executeChache(ProOrder order,String flag,String vin){ String driverCode=order.getProVehicle().getModelCode();//车型编码 if(DateUtils.unionInsured.equals(flag)){ //获取缓存 return (LastCoreInfo)memcachedAdapter.getFromCache(DateUtils.unionInsured,vin+driverCode); }else if(DateUtils.singleBusiness.equals(flag)){ //商业险 return (LastCoreInfo)memcachedAdapter.getFromCache(DateUtils.singleBusiness,vin+driverCode); }else{ //交强险 return (LastCoreInfo)memcachedAdapter.getFromCache(DateUtils.singleTraffic,vin+driverCode); } } }
策略模式应用总结:
优点:1、 相关算法系列 Strategy层次为客户端定义了一系列的可供重用的算法或行为。
继承有助于析取出这些算法中的公共功能。
2、 消除了客户端一些if else条件语句 :当不同的行为堆砌在一个类中时 ,
很难避免使用条件语句来选择合适的行为。
含有许多条件语句的代码通常意味着需要使用Strategy模式。
缺点:
1、客户端必须知道所有的策略类,或者交由中间类进行判断,并自行决定使用哪一个策略类。
2、并没有真正消除if else 对策略的选择,只是由客户端移除到了简单工厂
可以通过反射进一步消除if else 选择判断
3 、策略模式将造成产生很多策略类
4、无法支持策略的重叠,就是说我们同一时间只能采用一种策,针对复合策略需要加入更多的设计
相关文章推荐
- 项目重构 策略模式应用
- 一个应用策略模式(Strategy)的小实例----对TreeView功能菜单的功能选择模块进行解耦重构
- 5. php设计模式:策略模式的实际应用
- 简析设计模式之工厂模式与策略模式的实际组合应用
- 快速原型开发模式在实际开发过程中的应用
- 策略模式的应用
- 游戏项目中运用到的设计模式(二)...策略模式(strategy)(《重构-改善既有代码的设计》读后做)
- 从设计模式到实际应用
- 接口应用——策略模式
- android开发中观察者模式的实际应用
- 应用泛型的策略模式
- Java 接口应用案例 (策略设计模式使用)
- 应用泛型的策略模式
- Java 8 Strategy(策略设计模式)lambdas表达式应用
- SLF4J 的几种实际应用模式--之二:SLF4J+Logback
- 项目设计之一-------------策略模式应用
- SLF4J 的几种实际应用模式--:SLF4J+Log4J 与 SLF4J+LogBack
- 策略模式在游戏客户端中的应用
- JAVA设计模式-策略模式应用实例
- 常用设计模式的小结和实际中的应用