美文网首页
代码优雅之道——如何干掉过多的if else

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

作者: Java程序员YY | 来源:发表于2023-04-24 10:12 被阅读0次

    1、前言

    注意标题是过多的,所以三四个就没必要干掉了。实际开发中我们经常遇到判断条件很多的情况,比如下图有20多种情况,不用想肯定是要优化代码的,需要思考的是如何去优化?

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

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

    网上有两种见解:

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

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

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

        @Test
        void contextLoads() {
            testIf(100000);
            System.gc();
            testSwitch(100000);
        }
    
        private void testIf(Integer param) {
            long start = System.currentTimeMillis();
            for (int i = 0; i < param; i++) {
                if (i == param-1){
                    System.out.println("if判断100000次");
                }
            }
            long end = System.currentTimeMillis();
            long total = end - start;
            System.out.println("Test消耗时间:" + total);
        }
    
        private void testSwitch(Integer param){
            long start = System.currentTimeMillis();
            for (int i = 0; i < param; i++) {
                switch (i){
                    case 99999:
                        System.out.println("switch判断100000次");
                        break;
                }
            }
            long end = System.currentTimeMillis();
            long total = 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可以让代码清晰明了。当每种情况对应的业务逻辑复杂时,建议使用策略+工厂模式。这里我们举个栗子:厂家每个季度要举行不同的活动,我们使用策略工厂模式来实现

    策略接口

    public interface Strategy {
    
        /**
         * 处理各种活动
         * @return
         */
        String dealActivity();
    }
    

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

    @Service
    public class SpringActivity implements Strategy{
        @Override
        public String dealActivity() {
            return "春季活动逻辑";
        }
    }
    

    策略类工厂

    public class StrategyFactory {
        public static Strategy execute(Integer levelCode){
            Strategy strategy = null;
            switch (levelCode){
                case 1:
                    strategy = new SpringActivity();
                    break;
                case 2:
                    strategy = new SummerActivity();
                    break;
                case 3:
                    strategy = new AutumnActivity();
                    break;
                case 4:
                    strategy = new WinterActivity();
                    break;
                default:
                    throw new IllegalArgumentException("活动编号错误");
            }
            return strategy;
        }
    }
    

    然后在service层中传入对应的编码即可 ,我这里省略了service

    @RestController
    public class TestController {
    
        @PostMapping("/dealActivity")
        public String dealActivity(Integer code){
            Strategy strategy = StrategyFactory.execute(1);
            return strategy.dealActivity();
        }
    }
    

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

    4、Map+函数式接口

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

    @Service
    public class ActivityStrategyService {
    
        public String dealSpringActivity(){
            return "春季活动逻辑";
        }
    
        public String dealSummerActivity() {
            return "夏季活动逻辑";
        }
    
        public String dealAutumnActivity() {
            return "秋季活动逻辑";
        }
    
        public String dealWinterActivity() {
            return "冬季活动逻辑";
        }
    }
    

    再写个活动Service

    @Service
    public class ActivityService {
    
        @Autowired
        private ActivityStrategyService activityStrategyService;
    
        @FunctionalInterface
        interface ActivityFunction<A>{
            //这里可以传参啊,我这里举例用不上参数
            //String dealActivity(A a);
         String dealActivity();
        }
    
        private final Map<Integer, ActivityFunction> strategyMap = new HashMap<>();
    
        /**
         * 初始化策略
         */
        @PostConstruct
        public void initDispatcher(){
            strategyMap.put(1,()->activityStrategyService.dealSpringActivity());
            strategyMap.put(2, ()-> activityStrategyService.dealSummerActivity());
            strategyMap.put(3, ()-> activityStrategyService.dealAutumnActivity());
            strategyMap.put(4, ()-> activityStrategyService.dealWinterActivity());
        }
    
        public String dealActivity(Integer code){
            ActivityFunction<Integer> function = strategyMap.get(code);
            //这里防止活动编号没匹配上,可以使用断言来判断从而抛出统一异常
            return function.dealActivity();
        }
    
    }
    

    改变Controller

    @RestController
    public class TestController {
    
        @Autowired
        private ActivityService activityService;
    
        @PostMapping("/dealActivity")
        public String dealActivity(Integer code){
    //        Strategy strategy = StrategyFactory.execute(1);
    //        return strategy.dealActivity();
            return activityService.dealActivity(code);
        }
    }
    

    相关文章

      网友评论

          本文标题:代码优雅之道——如何干掉过多的if else

          本文链接:https://www.haomeiwen.com/subject/ywrujdtx.html