• JAVA:如何优雅地书写if-else(策略模式、函数式接口、卫语句)


    0. 引言

    在日常开发中我们常常遇到有多个if else的情况,之间书写显得代码冗余难看,对于追求更高质量代码的同学,就会思考如何优雅地处理这种代码

    下面我们来探讨下几种优化if else的方法

    1. switch

    switch方法针对枚举值处理有不错的效果,比如针对不同的订单状态时要做不同的处理,因为状态值有限,这时我们就可以直接使用switch来针对不同状态做不同的处理:

    原语句

    public void before(Integer status) {
            if(status == 1){
                System.out.println("订单未接单");
            }else if(status == 2){
                System.out.println("订单未发货");
            }else if(status == 3){
                System.out.println("订单未签收");
            }else{
                System.out.println("订单已签收");
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    switch

    public void greater(Integer status) {
            switch (status){
                case 1:
                    System.out.println("订单未接单");
                    break;
                case 2:
                    System.out.println("订单未发货");
                    break;
                case 3:
                    System.out.println("订单未签收");
                    break;
                default:
                    System.out.println("订单已签收");
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    总结:
    switch语句适用于判断条件有限且不需要经过复杂的计算,处理语句简单的场景。如果我们的判断条件需要经过一系列复杂的计算才能得到,或者处理语句逻辑也比较复杂时,我们就要考虑其他的处理方式了,毕竟在case中书写一大堆处理语句并不算得让人舒适的事情

    2. 函数式接口

    针对比较复杂的处理逻辑时,我们偏向于将这些处理逻辑单独抽离出来,而不是还放在一个方法里处理,增加整体的可读性和解耦性,也是我们衍生出利用函数式接口来处理if else的模式

    函数式接口map处理if else的要义,是将各个条件的复杂处理逻辑单独抽取为一个函数式接口方法,通过统一的判断条件来调用不同的方法,具体示例如下

    @Component
    public class FunctionInterfaceStrategy {
    
        /**
         * key 方法参数,多个参数可以自定义一个实体类处理
         * value 方法返回值
         */
        private Map<Integer, Function<Object,Boolean>> operationMap;
    
        @PostConstruct
        private void init(){
            operationMap = new HashMap<>();
            operationMap.put(1,this::takeOrder);
            operationMap.put(2,this::sendOrder);
            operationMap.put(3,this::signOrder);
            operationMap.put(4,this::finishOrder);
        }
    
        public Boolean doOperation(Object params,Integer status){
            return operationMap.get(status) == null || operationMap.get(status).apply(params);
        }
    
        private Boolean takeOrder(Object params){
            // TODO 比较复杂的处理逻辑
            System.out.println("订单未接单");
            return true;
        }
    
        private Boolean sendOrder(Object params){
            // TODO 比较复杂的处理逻辑
            System.out.println("订单未发货");
            return true;
        }
    
        private Boolean signOrder(Object params){
            // TODO 比较复杂的处理逻辑
            System.out.println("订单未签收");
            return true;
        }
    
        private Boolean finishOrder(Object params){
            // TODO 比较复杂的处理逻辑
            System.out.println("订单已签收");
            return true;
        }
    
    }
    
    • 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
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    调用时就不用再用if else区分了,直接传入参数到function map中调用

       @Autowired
        private FunctionInterfaceStrategy functionInterfaceStrategy;
        
        
        functionInterfaceStrategy.doOperation("参数",1);
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    当然我们上述演示的是有参数有返回值的函数式接口,实际生产中我们可能还需要其他形式的函数式接口,我们将其单独罗列出来,供大家参考使用

    接口名称说明调用方法
    Supplier无参数,有返回值get
    Consumer有参数,无返回值accept
    Runnable无参数,无返回值run
    Function有参数,有返回值apply

    3. 策略模式

    上述的函数式接口的形式,实际上是针对方法进行了分离,所有的实现方法还是放在了一个类里,即使你可以在FunctionInterfaceStrategy类中通过依赖注入的形式再次调用其他类的方法,但是这样的模式,已经趋近于我们要将的下一种方法,即使用策略模式来解决 if else

    策略模式的形式适用于实现方法更加复杂的情况,需要将处理逻辑解耦的更加干净的场景

    1、首先我们需要创建一个接口类,用来规定我们后续的实现类的格式

    public interface OrderStrategy {
    
        /**
         * 获取实现类标识
         * @return
         */
        Integer getType();
    
        /**
         * 逻辑处理
         * @param params
         * @return
         */
        Boolean handler(Object params);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2、其次针对每个判断条件创建一个实现类

    @Service
    public class SendOrderStrategy implements OrderStrategy{
    
        @Override
        public Integer getType() {
            return 2;
        }
    
        @Override
        public Boolean handler(Object params) {
            // TODO 复杂的处理逻辑
            System.out.println("订单未发货");
            return true;
        }
    }
    
    @Service
    public class SignOrderStrategy implements OrderStrategy{
    
        @Override
        public Integer getType() {
            return 3;
        }
    
        @Override
        public Boolean handler(Object params) {
            // TODO 复杂的处理逻辑
            System.out.println("订单未签收");
            return true;
        }
    }
    
    @Service
    public class TakeOrderStrategy implements OrderStrategy{
    
        @Override
        public Integer getType() {
            return 1;
        }
    
        @Override
        public Boolean handler(Object params) {
            // TODO 复杂的处理逻辑
            System.out.println("订单未接单");
            return true;
        }
    }
    
    
    • 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
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    3、创建一个策略工厂类,承装实现类

    @Component
    @AllArgsConstructor
    public class OrderStrategyFactory {
    
        private final List<OrderStrategy> orderStrategyList;
    
        private static Map<Integer,OrderStrategy> strategyMap = new HashMap<>();
    
        @PostConstruct
        private void init(){
            for (OrderStrategy orderStrategy : orderStrategyList) {
                strategyMap.put(orderStrategy.getType(),orderStrategy);
            }
        }
    
        /**
         * 执行方法
         * @param status
         * @param params
         * @return
         */
        public Boolean handler(Integer status,Object params){
            return strategyMap.get(status).handler(params);
        }
    
    }
    
    • 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

    4、方法调用

    @RestController
    @RequestMapping("ifelse")
    @AllArgsConstructor
    public class IfElseController {
    
        private final OrderStrategyFactory orderStrategyFactory;
    
        @GetMapping("strategy")
        public Boolean strategy(Integer status){
            return orderStrategyFactory.handler(status,"1");
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    总结:
    通过上述的代码示例,大家其实可以发现,函数式接口和策略模式有异曲同工之处,根本区别在于是否需要将实现方法单独抽取为一个实现类。抽取的粒度越细也就说明解耦越强

    使用策略模式,后续如果需要增加if else条件的话,只需要增加实现类即可,针对后续的处理更加方便

    最终使用哪一个还需要根据具体的业务情况而定

    4. 卫语句

    我们经常需要在方法前处理各种参数嵌套判断逻辑,如果不满足条件就直接返回了,这种情况更加推荐使用卫语句来处理

    原语句

    	public void before(Integer status) {
            if(status != null) {
                if(status != 0){
                    if(status == 1){
                        System.out.println("订单未接单");
                    }
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    卫语句

    	public void greater(Integer status) {
            if(status == null){
                return;
            }
            if(status != 0){
                return;
            }
            if(status == 1){
                System.out.println("订单未接单");
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    总结

    本期针对if else的处理就到此结束了,多看不如一试,要想理解的更深刻,还需要大家在实际开发中真正落实

  • 相关阅读:
    go学习(三、面向对象)
    2种方法,jmeter用一个正则提取器提取多个值!
    Java下打印一个等腰三角型
    一、Node.js 环境安装 (详)
    MySQL Exception -- Install/Remove of the Service Denied!
    redis实战-实现笔记点赞和点赞排行榜
    集合框架——LinkedList集合源码分析
    spring:简介
    揭秘华为云GaussDB(for Influx)最佳实践:hint查询
    BiMPM实战文本匹配【上】
  • 原文地址:https://blog.csdn.net/qq_24950043/article/details/122515062