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

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

案例

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

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

  1. public int calculate(int a, int b, String operator) {
  2. int result = Integer.MIN_VALUE;
  3. if ("add".equals(operator)) {
  4. result = a + b;
  5. } else if ("multiply".equals(operator)) {
  6. result = a * b;
  7. } else if ("divide".equals(operator)) {
  8. result = a / b;
  9. } else if ("subtract".equals(operator)) {
  10. result = a - b;
  11. }
  12. return result;
  13. }

当然也可以用switch来实现。

  1. public int calculateUsingSwitch(int a, int b, String operator) {
  2. switch (operator) {
  3. case "add":
  4. result = a + b;
  5. break;
  6. // other cases
  7. }
  8. return result;
  9. }

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

重构

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

  1. public interface Operation {
  2. int apply(int a, int b);
  3. }

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

  1. public class Addition implements Operation {
  2.  
  3. @Override
  4. public int apply(int a, int b) {
  5. return a + b;
  6. }
  7. }

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

  1. public class OperatorFactory {
  2. static Map<String, Operation> operationMap = new HashMap<>();
  3. static {
  4. operationMap.put("add", new Addition());
  5. operationMap.put("divide", new Division());
  6. // more operators
  7. }
  8.  
  9. public static Optional<Operation> getOperation(String operator) {
  10. return Optional.ofNullable(operationMap.get(operator));
  11. }
  12. }

调用

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

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

2、使用枚举

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

  1. public enum Operator {
  2. ADD, MULTIPLY, SUBTRACT, DIVIDE
  3. }

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

 
  1. ADD {
  2. @Override
  3. public int apply(int a, int b) {
  4. return a + b;
  5. }
  6. },
  7. // other operators
  8. public abstract int apply(int a, int b);

调用时直接传入枚举值

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

3、命令模式

定义命令接口。

  1. public interface Command {
  2. Integer execute();
  3. }

实现加法

 
  1. public class AddCommand implements Command {
  2. // Instance variables
  3. public AddCommand(int a, int b) {
  4. this.a = a;
  5. this.b = b;
  6. }
  7.  
  8. @Override
  9. public Integer execute() {
  10. return a + b;
  11. }
  12. }

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

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

测试代码

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

4、规则引擎

定义规则接口

 
  1. public interface Rule {
  2. boolean evaluate(Expression expression);
  3. Result getResult();
  4. }

实现规则引擎

 
  1. public class RuleEngine {
  2.  
  3. private static List<Rule> rules = new ArrayList<>();
  4. static {
  5. rules.add(new AddRule());
  6. }
  7.  
  8. public Result process(Expression expression) {
  9. Rule rule = rules.stream()
  10. .filter(r -> r.evaluate(expression))
  11. .findFirst()
  12. .orElseThrow(() -> new IllegalArgumentException("Expression does not matches any Rule"));
  13. return rule.getResult();
  14. }
  15. }

定义表达式

  1. public class Expression {
  2. private Integer x;
  3. private Integer y;
  4. private Operator operator;
  5. }

定义加法规则

  1. public class AddRule implements Rule {
  2.  
  3. @Override
  4. public boolean evaluate(Expression expression) {
  5. boolean evalResult = false;
  6. if (expression.getOperator() == Operator.ADD) {
  7. this.result = expression.getX() + expression.getY();
  8. evalResult = true;
  9. }
  10. return evalResult;
  11. }
  12. }

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

  1. @Test
  2. public void whenNumbersGivenToRuleEngine_thenReturnCorrectResult() {
  3. Expression expression = new Expression(5, 5, Operator.ADD);
  4. RuleEngine engine = new RuleEngine();
  5. Result result = engine.process(expression);
  6.  
  7. assertNotNull(result);
  8. assertEquals(10, result.getValue());
  9. }

总结虽然说常见的代码中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”领取学习实战资料;

 

Java中大量if...else语句的消除替代方案的更多相关文章

  1. 【转】Java中try catch finally语句中含有return语句的执行情况(总结版)

    Java中try catch finally语句中含有return语句的执行情况(总结版) 有一点可以肯定,finally块中的内容会先于try中的return语句执行,如果finall语句块中也有r ...

  2. java中的Switch case语句

    java中的Switch case 语句 在Switch语句中有4个关键字:switch,case break,default. 在switch(变量),变量只能是整型或者字符型,程序先读出这个变量的 ...

  3. Java中try、finally语句中有return时的执行情况 [转]

    原文:http://kingj.iteye.com/blog/1436761 在Java中当try.finally语句中包含return语句时,执行情况到底是怎样的,finally中的代码是否执行,大 ...

  4. Java中try catch finally语句中含有return语句的执行情况(总结版)

    在这里看到了try >但有一点是可以肯定的,finally块中的内容会先于try中的return语句执行,如果finall语句块中也有return语句的话,那么直接从finally中返回了,这也 ...

  5. Java中try catch finally语句中含有return语句的执行情况

    finally块中的内容会先于try中的return语句执行,如果finall语句块中也有return语句的话,那么直接从finally中返回了,这也是不建议在finally中return的原因.下面 ...

  6. Java中try catch finally语句中含return语句的执行情况总结-编程陷阱

    前言:有java编程基础的人对java的异常处理机制都会有一定了解,而且可能感觉使用起来也比较简单,但如果在try catch finally语句块中遇到return语句,开发者可能就会遇到一些逻辑问 ...

  7. Java | 在 Java 中执行动态表达式语句: 前中后缀、Ognl、SpEL、Groovy、Jexl3

    在一些规则集或者工作流项目中,经常会遇到动态解析表达式并执行得出结果的功能. 规则引擎是一种嵌入在应用程序中的组件,它可以将业务规则从业务代码中剥离出来,使用预先定义好的语义规范来实现这些剥离出来的业 ...

  8. java 中 printf()语句的理解

    对print和println的理解很简单,今天突然接触到printf(),有点懵,整理了下也帮自己理一理 printf是格式化输出的形式 下在举个例子: package other; public c ...

  9. Java中循环与选择语句

    public class Ifelse{ public static void main(String [] args){ int score=98; if(score>=90&& ...

随机推荐

  1. 集合 Enumerable Enumerator yield

    集合: 通过索引来访问成员,--引申到索引器 的使用 for foreach循环遍历 --引申到 IEnumerable IEnumerator(会引申到yield) 常用的集合操作,add, ins ...

  2. C# 从零开始写 SharpDx 应用 画三角

    原文:C# 从零开始写 SharpDx 应用 画三角 版权声明:博客已迁移到 https://blog.lindexi.com 欢迎访问.如果当前博客图片看不到,请到 https://blog.lin ...

  3. 【批量添加】-SqlBulkCopy语句 标签: sql批量添加 2015-12-20 14:39 1367人阅读 评论(33)

    上篇博客我们介绍了通过拼接sql字符串的方法来对sql数据库进行批量添加,但是通过语句拼接insert语句有个缺点,就是每次最多只能添加1000条.当时我们另外一个界面也用到了批量添加,但是这个界面轻 ...

  4. Java练习 SDUT-1239_水仙花数

    水仙花数 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 春天是鲜花的季节,水仙花就是其中最迷人的代表,数学上有个水仙花 ...

  5. @gym - 101137K@ Knights of the Old Republic

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定 N 个点 M 条边的一张图. 每个点有两个属性 Ai, B ...

  6. jQuery Callback

    Callback 函数在当前动画 100% 完成之后执行. jQuery 动画的问题 许多 jQuery 函数涉及动画.这些函数也许会将 speed 或 duration 作为可选参数. 例子:$(& ...

  7. PyTorch入门学习(二):Autogard之自动求梯度

    autograd包是PyTorch中神经网络的核心部分,简单学习一下. autograd提供了所有张量操作的自动求微分功能. 它的灵活性体现在可以通过代码的运行来决定反向传播的过程, 这样就使得每一次 ...

  8. HZOJ 回家

    这篇博客大部分在写我的错解……明明很简单的一道题,知道正解后10分钟AC,然而几个错解打的想死…… 错解1 WA40: 鬼知道这40分哪来的……这也是考试最后很无奈地交上去的代码,最后剩20分钟时发现 ...

  9. OpenResty,X-WAF防火墙相关

    >>OpenResty<< >>Lua教程<< >>反向代理百度百科<< >>X-WAF配置指南<<

  10. hdu 1430 魔板 (BFS+预处理)

    Problem - 1430 跟八数码相似的一题搜索题.做法可以是双向BFS或者预处理从"12345678"开始可以到达的所有状态,然后等价转换过去直接回溯路径即可. 代码如下: ...