zoukankan      html  css  js  c++  java
  • 设计模式——策略模式

      在项目中看到茫茫多的if else,相信每一个有追求的程序员都会有优化的欲望。策略模式就是一种很好的优化途径。刚好最近在项目中实践了一次策略模式,不敢说是最佳实践,但也算是个人的一次实践经验分享。场景如下:

      业务需要将网络上来源不同的数据文件解析,然后将解析得到的数据插入数据库。那么代码在这里主要做3件事情:
      1、解析数据,得到数据实体对象POJO1;

      2、将得到的数据实体转换成方便插入数据库的数据实体POJO2;

      3、将POJO2插入数据库。

      由于公司代码无法共享,本文使用伪代码说明:

      优化前大概是这样的:

        if (来源A)
            解析数据A
            转换实体A1-A2   
        else if (来源B)
            解析数据B1-B2
            转换实体B 
        else if(...)
            ......
        else
            ....
        .......
        if (来源A)
            实体A1迭代插入数据库
        else if (来源B)
            是实体B2迭代插入数据库
        else if (...)
            ......
        else 
            ......

      上面的代码显然很不优雅,虽然是做相同的事情,却写了这么一大堆的if else,后续如果新增来源,还得增加,很不利于维护。这里我们可以实现一个策略接口Stragtegy,然后根据业务(这里是不同的数据来源)创建其实现类StragtegyImplA,StragtegyImplB.......

    //F, T泛型分别代表转换前和转换后的POJO类型
    interface Strategy<F, T> {
        //通过来源source解析数据
        //实现类根据业务实现从不同的数据库解析,从excel解析等
        List<F> doParseData(source);
        // 数据转换
        //通过泛型F,T表示转换前后的POJO,减少if else判断
        List<T> transferPOJO(List<F> fromPOJOs);
        //保存数据
        //实现类根据业务实现保存不同的数据库,或者保存到文件
        saveData(List<T> toPOJOs);
    }

      实现类这里就省略了,相信不影响大家理解思路,这样我们就把变化的部分都封装到了不同的策略实现类里面StragtegyImplA,StragtegyImplB.......,那么问题来了,在原来调用的地方应该怎么知道该创建哪个类型的策略实现类呢?方法有很多,我这里用了枚举配合工厂方法实现。将文件来源source保存在枚举类Enum中,通过在工厂类中判断枚举类型,返回不同的策略实现类。实际上,根据业务需要,还可以增加一个上下文类Context,但这里的业务场景还不需要这么高的封装程度,暂时省略这个类。

      优化后是这样的:

        Strategy strategyImpl = StrategyFactory.createStrategyImpl(各种数据来源)
        List<F> fromList = strategyImpl.doParseData(...);
        List<T> toList = strategyimpl.tranferPOJO(fromList);
        saveData(toList);

    烦人的if else没了,看起来果然清爽很多。但是代码看起来还是很繁琐,这里我们再次审视一次业务需要做的三件事情

      1、解析数据,得到数据实体对象POJO1;

      2、将得到的数据实体转换成方便插入数据库的数据实体POJO2;

      3、将POJO2插入数据库。

    对照接口的三个方法,其实第1、2个方法解析数据和转换POJO返回的结果都属于“中间数据”,都是为了第3个方法保存数据库使用的,这里我们就可以通过在实现saveData的时候这样做

    public  XXXStrategyImpl implements Strategy<F,T> {
        .....
        saveData(List<T> toList) {
        doParseData(...);
        transferPOJO(...);
        .........(这里才真正开始保存业务的逻辑)
    }

    这样就更简洁了,当然也是建立在具体的业务上,实践需要结合自身的业务场景。

      策略模式缺点也总结一下:

      1、在策略类型超过大概5种时,策略模式对调用者代码阅读水平要求就比较高了,调用者必须理解各个策略的算法才能更好地使用

      2、if else减少了,但是类却增多了,也是一个需要权衡自身情况的tradeoff吧

      3、策略必须暴露给调用者,违反迪米特法则。

  • 相关阅读:
    项目总结—校园办公管理系统(SSM框架搭建)
    sssp-webservce_restful
    angular 中怎么获取路径上的参数 参考:https://docs.angularjs.org/api/ng/service/$location
    spring mvc 解决json 不能转换的问题
    在 html中怎么获取中的参数
    弹框,图标
    sssp maven pom
    spring中 的MD5 加密
    angularjs 整合 bootstrap
    深入理解Java包装类与自动拆装箱
  • 原文地址:https://www.cnblogs.com/junqiao/p/9801672.html
Copyright © 2011-2022 走看看