1、前言
实际开发中我们经常遇到判断条件很多的情况,比如下图有20多种情况,不用想肯定是要优化代码的,需要思考的是如何去优化?
网上很多说用switch case啊,首先不比较if else与switch case效率问题的,只从代码整洁度来看二者没啥区别啊!我们这里更重要的是代码整洁度问题,为什么呢?来看下文的比较。
2、If else与switch case效率真的差距很大么?
网上有两种见解:
第一种是说switch…case会生成一个跳转表来指示实际的case分支的地址,而这个跳转表的索引号与switch变量的值是相等的。从而,switch…case不用像if…else那样遍历条件分支直到命中条件,而只需访问对应索引号的表项从而到达定位分支的目的。简单来说就是以空间换时间
第二种是说二者效率上差距并不大
于是我们自己去体验一下,不存在复杂业务逻辑,仅仅比较两种方式的效率:
voidcontextLoads() { testIf(100000); System.gc(); testSwitch(100000); } privatevoidtestIf(Integerparam) { longstart=System.currentTimeMillis(); for (inti=0; i<param; i++) { if (i==param-1){ System.out.println("if判断100000次"); } } longend=System.currentTimeMillis(); longtotal=end-start; System.out.println("Test消耗时间:"+total); } privatevoidtestSwitch(Integerparam){ longstart=System.currentTimeMillis(); for (inti=0; i<param; i++) { switch (i){ case99999: System.out.println("switch判断100000次"); break; } } longend=System.currentTimeMillis(); longtotal=end-start; System.out.println("Test消耗时间:"+total); }
可见差距并不大。而情况太多的时候谁还会去用if else和switch case呢?下面还是对两种方式的使用场景做简单的分析:
if else能够把复杂的逻辑关系表达得清晰、易懂,包容了程序执行的各种情况。
switch不适合业务系统的实际复杂需求,业务不断的变更迭代,一更改需求,条件的复杂度高了,switch无力处理。switch经常忘记写break,估计很多人一不小心就忘记写了。switch…case只能处理case为常量的情况。当情况不大于5种并且单一变量的值(如枚举),此时我们就可以使用switch,它的可读性比if条件更清晰。
除了上述说到枚举的这种场景,建议使用switch,其他个人愚见:只要情况不大于5种就直接使用if else
3、策略+工厂模式
上述说到情况较少时并且业务逻辑不复杂的使用if else可以让代码清晰明了。当每种情况对应的业务逻辑复杂时,建议使用策略+工厂模式。这里我们举个栗子:厂家每个季度要举行不同的活动,我们使用策略工厂模式来实现
策略接口
publicinterfaceStrategy { /*** 处理各种活动* @return*/StringdealActivity(); }
然后春夏秋冬四季活动类实现该接口
publicclassSpringActivityimplementsStrategy{ publicStringdealActivity() { return"春季活动逻辑"; } }
策略类工厂
publicclassStrategyFactory { publicstaticStrategyexecute(IntegerlevelCode){ Strategystrategy=null; switch (levelCode){ case1: strategy=newSpringActivity(); break; case2: strategy=newSummerActivity(); break; case3: strategy=newAutumnActivity(); break; case4: strategy=newWinterActivity(); break; default: thrownewIllegalArgumentException("活动编号错误"); } returnstrategy; } }
然后在service层中传入对应的编码即可 ,我这里省略了service
publicclassTestController { "/dealActivity") (publicStringdealActivity(Integercode){ Strategystrategy=StrategyFactory.execute(1); returnstrategy.dealActivity(); } }
上述已经干掉了if else ,后续季度活动调整去修改对应活动策略类中逻辑即可。缺点:如果情况比这多,那么策略类会越来越多,也就是所谓的策略类膨胀,并且没有没有一个地方可以俯视整个业务逻辑。
4、Map+函数式接口
将上述策略类全部作为方法
publicclassActivityStrategyService { publicStringdealSpringActivity(){ return"春季活动逻辑"; } publicStringdealSummerActivity() { return"夏季活动逻辑"; } publicStringdealAutumnActivity() { return"秋季活动逻辑"; } publicStringdealWinterActivity() { return"冬季活动逻辑"; } }
再写个活动Service
publicclassActivityService { privateActivityStrategyServiceactivityStrategyService; interfaceActivityFunction<A>{ //这里可以传参啊,我这里举例用不上参数//String dealActivity(A a);StringdealActivity(); } privatefinalMap<Integer, ActivityFunction>strategyMap=newHashMap<>(); /*** 初始化策略*/publicvoidinitDispatcher(){ strategyMap.put(1,()->activityStrategyService.dealSpringActivity()); strategyMap.put(2, ()->activityStrategyService.dealSummerActivity()); strategyMap.put(3, ()->activityStrategyService.dealAutumnActivity()); strategyMap.put(4, ()->activityStrategyService.dealWinterActivity()); } publicStringdealActivity(Integercode){ ActivityFunction<Integer>function=strategyMap.get(code); //这里防止活动编号没匹配上,可以使用断言来判断从而抛出统一异常returnfunction.dealActivity(); } }
改变Controller
publicclassTestController { privateActivityServiceactivityService; "/dealActivity") (publicStringdealActivity(Integercode){ // Strategy strategy = StrategyFactory.execute(1);// return strategy.dealActivity();returnactivityService.dealActivity(code); } }