zoukankan      html  css  js  c++  java
  • Java中大量if...else语句的消除替代方案

    在我们平时的开发过程中,经常可能会出现大量If else的场景,代码显的很臃肿,非常不优雅。那我们又没有办法处理呢?

    针对大量的if嵌套让代码的复杂性增高而且难以维护。本文将介绍多种解决方案。

    案例

    下面模拟业务逻辑,根据传入的条件作出不同的处理方式。

    拿一个计算器类当做案例,有加减乘除四种方法,输出结果和四种操作有关。

    public int calculate(int a, int b, String operator) {
        int result = Integer.MIN_VALUE;
        if ("add".equals(operator)) {
            result = a + b;
        } else if ("multiply".equals(operator)) {
            result = a * b;
        } else if ("divide".equals(operator)) {
            result = a / b;
        } else if ("subtract".equals(operator)) {
            result = a - b;
        }
        return result;
    }

    当然也可以用switch来实现。

    public int calculateUsingSwitch(int a, int b, String operator) {
        switch (operator) {
          case "add":
            result = a + b;
            break;
            // other cases
        }
        return result;
    }

    随着条件越来越多,复杂性也增高,也越来越难以维护。

    重构

    1、工厂类我们将操作进行抽象给出一个操作接口

    public interface Operation {
        int apply(int a, int b);
    }

    然后实现加减乘除四个方法

    public class Addition implements Operation {
        
        @Override
        public int apply(int a, int b) {
            return a + b;
        }
    }

    然后通过操作工厂提供操作

    public class OperatorFactory {
        static Map<String, Operation> operationMap = new HashMap<>();
        static {
            operationMap.put("add", new Addition());
            operationMap.put("divide", new Division());
            // more operators
        }
        
        public static Optional<Operation> getOperation(String operator) {
            return Optional.ofNullable(operationMap.get(operator));
        }
    }

    调用

    public int calculateUsingFactory(int a, int b, String operator) {
        Operation targetOperation = OperatorFactory
          .getOperation(operator)
          .orElseThrow(() -> new IllegalArgumentException("Invalid Operator"));
        return targetOperation.apply(a, b);
    }

    新增操作只需要维护操作工厂的operationMap即可。

    2、使用枚举

    在枚举中定义操作,如下:

    public enum Operator {
        ADD, MULTIPLY, SUBTRACT, DIVIDE
    }

    然而不同的操作对应的逻辑不一样,我们编写抽象方法

     
    ADD {
        @Override
        public int apply(int a, int b) {
            return a + b;
        }
    },
    // other operators
    public abstract int apply(int a, int b);

    调用时直接传入枚举值

    public int calculate(int a, int b, Operator operator) {
        return operator.apply(a, b);
    }
    @Test
    public void whenCalculateUsingEnumOperator_thenReturnCorrectResult() {
        Calculator calculator = new Calculator();
        int result = calculator.calculate(3, 4, Operator.valueOf("ADD"));
        assertEquals(7, result);
    }

    3、命令模式

    定义命令接口。

    public interface Command {
        Integer execute();
    }

    实现加法

     
    public class AddCommand implements Command {
        // Instance variables
        public AddCommand(int a, int b) {
            this.a = a;
            this.b = b;
        }
    
        @Override
        public Integer execute() {
            return a + b;
        }
    }

    定义一个Calculator类,加入执行命令的方法。

    public int calculate(Command command) {
        return command.execute();
    }

    测试代码

     
    @Test
    public void whenCalculateUsingCommand_thenReturnCorrectResult() {
        Calculator calculator = new Calculator();
        int result = calculator.calculate(new AddCommand(3, 7));
        assertEquals(10, result);
    }

    4、规则引擎

    定义规则接口

     
    public interface Rule {
        boolean evaluate(Expression expression);
        Result getResult();
    }

    实现规则引擎

     
    public class RuleEngine {
    
        private static List<Rule> rules = new ArrayList<>();
        static {
            rules.add(new AddRule());
        }
        
        public Result process(Expression expression) {
            Rule rule = rules.stream()
              .filter(r -> r.evaluate(expression))
              .findFirst()
              .orElseThrow(() -> new IllegalArgumentException("Expression does not matches any Rule"));
            return rule.getResult();
        }
    }

    定义表达式

    public class Expression {
        private Integer x;
        private Integer y;
        private Operator operator;
    }

    定义加法规则

    public class AddRule implements Rule {
    
        @Override
        public boolean evaluate(Expression expression) {
            boolean evalResult = false;
            if (expression.getOperator() == Operator.ADD) {
                this.result = expression.getX() + expression.getY();
                evalResult = true;
            }
          return evalResult;
        }
    }

    给规则引擎传入表达式来调用

    @Test
    public void whenNumbersGivenToRuleEngine_thenReturnCorrectResult() {
        Expression expression = new Expression(5, 5, Operator.ADD);
        RuleEngine engine = new RuleEngine();
        Result result = engine.process(expression);
    
        assertNotNull(result);
        assertEquals(10, result.getValue());
    }

    总结虽然说常见的代码中if...else不可避免,但滥用 if...else 会对代码的可读性、可维护性造成很大伤害。因此,使用好 if...else,让代码清爽对于你的项目长远考虑有十分重要的意义。

    英文原文:https://www.baeldung.com/java-replace-if-statements

    其他参考资料:

    策略设计模式:http://www.runoob.com/design-pattern/strategy-pattern.html

    命令设计模式:http://www.runoob.com/design-pattern/command-pattern.html

    推荐阅读:

    Java8中遍历Map的常用四种方式

    推荐一些MySQL优化技巧,效率提升不止十倍!

    44个Java代码优化手段,保证性能溜溜的!

    扫码关注公众号,发送关键词获取相关资料:
    1. 发“Springboot”领取电商项目实战源码;

    2. 发“SpringCloud”领取学习实战资料;

     
  • 相关阅读:
    web开发的性能准则(减少页面加载时间方面)
    HTTP
    HTTP -- 缓存
    新的博客地址
    mongodb 的命令操作(转)
    低调的css3属性font-size-adjust
    HTML5对表单的约束验证
    clientHeight , scrollHeight , offsetHeight之间的区别及兼容方案
    关于word-break和word-wrap的使用和区别
    MongoDB
  • 原文地址:https://www.cnblogs.com/lyn20141231/p/12110907.html
Copyright © 2011-2022 走看看