代码优雅之道——如何干掉过多的if else

简介: 代码优雅之道——如何干掉过多的if else

1、前言

实际开发中我们经常遇到判断条件很多的情况,比如下图有20多种情况,不用想肯定是要优化代码的,需要思考的是如何去优化?

网上很多说用switch case啊,首先不比较if else与switch case效率问题的,只从代码整洁度来看二者没啥区别啊!我们这里更重要的是代码整洁度问题,为什么呢?来看下文的比较。

2、If else与switch case效率真的差距很大么?

网上有两种见解:

第一种是说switch…case会生成一个跳转表来指示实际的case分支的地址,而这个跳转表的索引号与switch变量的值是相等的。从而,switch…case不用像if…else那样遍历条件分支直到命中条件,而只需访问对应索引号的表项从而到达定位分支的目的。简单来说就是以空间换时间

第二种是说二者效率上差距并不大

于是我们自己去体验一下,不存在复杂业务逻辑,仅仅比较两种方式的效率:

 

@TestvoidcontextLoads() {
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();
}

然后春夏秋冬四季活动类实现该接口

@ServicepublicclassSpringActivityimplementsStrategy{
@OverridepublicStringdealActivity() {
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

@RestControllerpublicclassTestController {
@PostMapping("/dealActivity")
publicStringdealActivity(Integercode){
Strategystrategy=StrategyFactory.execute(1);
returnstrategy.dealActivity();
    }
}

上述已经干掉了if else ,后续季度活动调整去修改对应活动策略类中逻辑即可。缺点:如果情况比这多,那么策略类会越来越多,也就是所谓的策略类膨胀,并且没有没有一个地方可以俯视整个业务逻辑。

4、Map+函数式接口

将上述策略类全部作为方法

@ServicepublicclassActivityStrategyService {
publicStringdealSpringActivity(){
return"春季活动逻辑";
    }
publicStringdealSummerActivity() {
return"夏季活动逻辑";
    }
publicStringdealAutumnActivity() {
return"秋季活动逻辑";
    }
publicStringdealWinterActivity() {
return"冬季活动逻辑";
    }
}

再写个活动Service

@ServicepublicclassActivityService {
@AutowiredprivateActivityStrategyServiceactivityStrategyService;
@FunctionalInterfaceinterfaceActivityFunction<A>{
//这里可以传参啊,我这里举例用不上参数//String dealActivity(A a);StringdealActivity();
    }
privatefinalMap<Integer, ActivityFunction>strategyMap=newHashMap<>();
/*** 初始化策略*/@PostConstructpublicvoidinitDispatcher(){
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

@RestControllerpublicclassTestController {
@AutowiredprivateActivityServiceactivityService;
@PostMapping("/dealActivity")
publicStringdealActivity(Integercode){
//        Strategy strategy = StrategyFactory.execute(1);//        return strategy.dealActivity();returnactivityService.dealActivity(code);
    }
}
相关文章
|
2月前
|
算法 程序员
为何程序员在编写程序时难以一次性将所有代码完美无瑕地完成,而是需要经历反复修改Bug的过程?
为何程序员在编写程序时难以一次性将所有代码完美无瑕地完成,而是需要经历反复修改Bug的过程?
19 7
|
3月前
|
小程序 机器人 Python
分享28个VX小程序源码,总有一款适合您
分享28个VX小程序源码,总有一款适合您
57 1
|
5月前
|
设计模式 存储 算法
谈谈代码:如何避免写出糟糕if...else语句
在写代码的日常中,`if...else`语句是极为常见的.正因其常见性,很多同学在写代码的时候并不会去思考其在目前代码中的用法是否妥当.而随着项目的日渐发展,糟糕的`if...else`语句将会充斥在各处,让项目的可维护性急剧下降.故在这篇文章中,笔者想和大家谈谈如何避免写出糟糕`if...else`语句.
29 0
谈谈代码:如何避免写出糟糕if...else语句
|
9月前
|
前端开发 JavaScript 开发工具
🎖️我只会使用前端框架开发不行吗?
我们经常看到一个现象:一些前端开发人员可能会在使用最新框架创建漂亮的网站的同时,却在编写基本的CSS样式或创建简单的JavaScript函数方面感到困难。
68 0
|
Java C语言
看似无害的代码如何搞垮系统
编程就像魔法。最近遇到一个诡异的问题:添加一段看似无害的简单代码后,系统原有功能不可用了。 ## 复现演示 jdk 8 可使用如下演示代码复现这个问题。 `TaskCenter` 是一个任务框架,可添加多个任务,随后框架将执行这些任务。 `First` 任务是新增代码,看起来简单无害,且看不出对原有任务 `Count` 有何影响,但添加 `First` 任务后,其自身执行正常,原本正常的 `C
102 0
|
算法 程序员 开发者
程序员大部分时间不是写代码,而是。。。
程序员大部分时间不是写代码,而是。。。
131 0
程序员大部分时间不是写代码,而是。。。
|
设计模式 算法 搜索推荐
长痛不如短痛,这次重构代码我干掉了 if-else
长痛不如短痛,这次重构代码我干掉了 if-else
153 0
|
自然语言处理 前端开发 安全
2021年了,你还在这样设计网站,会死人的啊
2021年了,你还在这样设计网站,会死人的啊
120 0
|
开发框架 .NET API
看过这么多爆文,依旧走不好异步编程这条路?​
本文带大家抓住异步编程async/await语法糖的牛鼻子: SynchronizationContext。
看过这么多爆文,依旧走不好异步编程这条路?​
|
Java
本来想用“{{”秀一波,结果却导致了内存溢出!(上)
本来想用“{{”秀一波,结果却导致了内存溢出!
100 0
本来想用“{{”秀一波,结果却导致了内存溢出!(上)