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

来源:互联网 发布:路易斯康 知乎 编辑:程序博客网 时间:2024/05/09 09:47

策略模式定义:定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换,使得算法可独立于使用它的客户而变化。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、无法支持策略的重叠,就是说我们同一时间只能采用一种策,针对复合策略需要加入更多的设计

原创粉丝点击