一、场景:
1 2 3 4 5 6 7 8 9 10 11
   | if (很复杂的条件A){        }else if (很复杂的条件B){        }else if (很复杂的条件C){        }else if (很复杂的条件D){        }else if (很复杂的条件E){        }
  | 
 
如上述代码,工作中经常遇到这种场景,导致代码的可读性较差。对后续代码的扩展维护来说,是巨大的灾难。
以上代码有以下几点问题:
后续增加任何功能,都需要在原来耦合的代码里添加代码,有可能会影响原有功能。
 
没有做到开闭原则,一段良好的代码需要做到对扩展开发,对修改关闭。
 
校验的逻辑都在一个类中,导致这个类中的代码很多,从而影响了代码的可读性、可维护性。
 
if-else条件判断很难懂,无法判断某个条件中的校验到底是校验哪种校验类型,每次查看这段代码都要研究好久。
 
二、解决:
使用策略工厂模式来解决以上问题,把每种校验的方式封装起来,然后通过策略工厂模式来路由下发,把冗长的代码解耦出来,形成了一套框架,并且保证了代码的扩展性。
2.1 创建策略工厂类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
   | public class CheckStrategyFactory {     private final Map<CheckStrategySelector, InterfaceCheck> strategyRegistry = new HashMap<>();
      @Autowired     public CheckStrategyFactory(ACheck aCheck, BCompare bCompare, CCheck cCheck, DCheck dCheck,                                 ASelector aSelector,BSelector bSelector,CSelector cSelector,DSelector dSelector) {
                   strategyRegistry.put(aSelector, aCheck);         strategyRegistry.put(bSelector, bCompare);         strategyRegistry.put(cSelector, cCheck);         strategyRegistry.put(dSelector, dCheck);              }
      public InterfaceCheck getStrategy(MatcheA ma, MatcheB mb) {
          for (Map.Entry<CheckStrategySelector, InterfaceCheck> entry : strategyRegistry.entrySet()) {             if (entry.getKey().matches(ma, mb)) {                 return entry.getValue();             }         }
          return null;      } }
  | 
 
2.2 创建策略选择接口和校验接口
创建2个接口,一个策略选择接口CheckStrategySelector,一个校验接口InterfaceCheck。
1 2 3
   | public interface CheckStrategySelector {     boolean matches(MatcheA ma, MatcheB mb); }
  | 
 
1 2 3
   | public interface InterfaceCheck {     CheckOutputModel check(CheckA ca, CheckB cb); }
  | 
 
2.3 实现策略选择接口和校验接口
再创建4个策略类和4个校验类分别实现策略选择接口CheckStrategySelector和校验接口InterfaceCheck。
下面仅展示一个,其他省略。
策略选择实现类
1 2 3 4 5 6 7
   | public class ASelector implements CheckStrategySelector {     @Override     public boolean matches(MatcheA ma, MatcheB mb) {                  return ma && mb;     } }
  | 
 
校验实现类
1 2 3 4 5 6 7
   | @Service("aCheck") public class ACheck implements InterfaceCheck {     @Override     public CheckOutputModel check(CheckA ca, CheckB cb) {              } }
  | 
 
2.4 改造if判断
最后“场景”章节中的if判断语句块,改造如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
   | @Service("commonCheckHandler") public class CommonCheckHandler implements CheckHandler{     private final CheckStrategyFactory factory;
      public CommonCheckHandler(CheckStrategyFactory factory) {         this.factory = factory;     }
      @Override     public CheckOutputModel doHandle(A paramA, B paramB, C paramC) throws Exception {         CheckOutputModel result = new CheckOutputModel();                  MatcheA ma = paramA.getMatcheA();          MatcheB mb = paramB.getMatcheB();
          InterfaceCheck interfaceCheckStrategy = factory.getStrategy(ma, mb);         if(interfaceCheckStrategy != null){             return interfaceCheckStrategy.check(paramC.getCheckA(), paramC.getCheckB());         } else {             result.setSuccess(false);             result.setErrorCode("未找到对应的校验策略");             return result;         }     } }
  | 
 
以上通过策略工厂模式把那段代码拆成了多个文件,通过策略工厂模式把冗长的if-else代码给分解了。

重构之后,创建了工厂类,由工厂类中的策略判断逻辑来决定是哪一种策略类型,在运行时动态确定使用哪种策略,最终路由到对应的校验方法里。
重构后的代码符合了开闭原则,添加新策略的时候,最小化、集中化代码改动、减少引入bug的风险。
 
重构后的代码解耦了之前代码的复杂度,解耦了策略的定义、创建和使用,控制代码复杂度,让每个部分的代码不至于太复杂、代码量过多。现在每个类的代码基本上在一显示屏就能展示完成。
 
增加了代码的可读性和可维护性。
 
三、总结
不是所有if-else分支都是烂代码,只要if-else分支不复杂,代码不多,这并没有问题,只要遵循KISS原则,怎么简单怎么来,就是最好的设计。
一旦if-else分支很多,且每个分支都包含很多复杂的逻辑判断,这个时候就可以考虑是不是通过策略模式可以更清晰的梳理代码,使得代码维护性更强。
1 2 3 4 5 6
   | 本文为个人知识学习,非原创!非作者!如本博客有侵权行为,请与我联系。 摘录以下文章,内容根据个人需求有所删减,尊重知识产出,尊重作者知识劳动成果。
  作者:阿里云开发者 汪峰(蔚风) 链接:https://mp.weixin.qq.com/s/tg4vTL6_TI-tnxaMyVLhsA 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
   |