您的位置:首页 > 其它

策略模式在需求重构中的实际应用

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)需要使用一个算法的不同变体。

实际需求情景图:



需求改造前的伪代码结构:

//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、无法支持策略的重叠,就是说我们同一时间只能采用一种策,针对复合策略需要加入更多的设计
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  重构 策略模式