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

策略模式定义:定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换,使得算法可独立于使用它的客户而变化。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设计图:

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、无法支持策略的重叠,就是说我们同一时间只能采用一种策,针对复合策略需要加入更多的设计

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值