设计模式——策略模式

  在项目中看到茫茫多的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、策略必须暴露给调用者,违反迪米特法则。

原文地址:https://www.cnblogs.com/junqiao/p/9801672.html