翻译 | 怎么在Java中替换掉繁杂的if语句

原文自工程师baeldung博客,传送门java

可关注咱们的收藏夹,最新的翻译文章都在这里。git

1. 概述

决策结构在大多数编程语言中占据了至为重要的一步。可是咱们经常会被大量的那种让代码变得难读且难维护的内嵌if语句搞得浑身难受。github

在此次的教程中,咱们未来过一下能够代替内嵌if语句的各类方法。让咱们来探索简化咱们代码的途径吧。express

2. 案例学习

一般咱们会遇到一些须要作一系列条件处理的业务逻辑,而且它们每个都须要不一样的处理。编程

为了演示,咱们来看一下Calulator(计算器)类的一个例子。上面是带有两个数字类型参数,一个操做符参数以及基于操做的数值返回值的一个方法:设计模式

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语句来操做:app

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

在典型的开发过程当中,本质上if语句会使程序变得更为臃肿和复杂。而且,switch语句也并不是全部场景都适用,当条件复杂的时候,switch语句就没什么做用了。编程语言

另外一个使用嵌套条件声明编程的影响是它使得程序变得难以管理。例如,若是咱们须要新添加一个操做,咱们须要添加一个新的if条件以及条件的实现。ide

3. 重构

让咱们尝试下使用其余更简洁和易管理的方法来代替这个复杂的if语句吧。学习

3.1 工厂类

不少时候咱们常常碰见许多条件声明,它们是用来处理每一个分支中类似的操做。这提供给咱们一个想法,提取一个返回具体类型的对象而且根据具体对象行为执行操做的工厂类

例如在下面,让咱们定义一个带有单独的apply方法的操做接口

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));
    }
}
复制代码

如今在Calculator类中,咱们可以经过查询工厂来获取相关的操做而且应用于其中:

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

在这个例子里,咱们能看到如何经过工厂类来将逻辑业务责任分发委托给一系列轻耦合对象当中。可是若是只是简单地将嵌套if语句转移成工厂类,这明显是不符合咱们的目的的。

做为另外的选择,咱们可以经过维护可以被快速查询的对象仓库map(映射),正如OperatorFactory#operationMap,来达成咱们的目的。咱们也可以在运行时定义映射对象而且配置它们用于查找。

3.2 使用枚举

除了映射对象(map)的使用以外,咱们也可使用枚举来标记特定的逻辑业务。在这以后,咱们能经过它来代替嵌套if语句或者swtich语句了。做为其余处理,咱们也可使用它们做为对象工厂而且整理用于处理相关的业务逻辑操做。

这会减小嵌套if语句的数量而且将业务责任委托给独立的枚举变量中。

让咱们来看看怎么去实现它。首先,咱们须要定义一个枚举类:

public enum Operator {
    ADD, MULTIPLY, SUBTRACT, DIVIDE
}
复制代码

像咱们看到这样,这些值是不一样操做符的标签,而且会运用到以后的计算当中。就像嵌套if语句和switch语句那样,咱们能够将这些值看成选项来使用。但和它们不一样的地方,让咱们去设计一种可以将逻辑委托给枚举自己的替代方法吧。

咱们为每个枚举量都定义了各自的方法而且进行了计算操做,例如:

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

而后在Calculator类中,咱们也定义了一个用于执行操做的方法:

public int calculate(int a, int b, Operator operator) {
    return operator.apply(a, b);
}
复制代码

如今,咱们能够经过使用Operator#valueOf()方法来将字符串转换为操做符来调用方法了:

@Test
public void whenCalculateUsingEnumOperator_thenReturnCorrectResult() {
    Calculator calculator = new Calculator();
    int result = calculator.calculate(3, 4, Operator.valueOf("ADD"));
    assertEquals(7, result);
}
复制代码

3.3 命令模式(command pattern)

在先前的讨论中,咱们已经看到使用工厂类来返回指定操做符的对应的业务对象实例了,稍后,业务对象实例将用于以后的Claculator中执行计算操做。

咱们也可以设计一个Calculator#calculate方法来接收一个能够执行输入的指令。这是另一种来代替嵌套if语句的方法。

首先咱们定义一个Command接口:

public interface Command {
    Integer execute();
}
复制代码

而后,让咱们实现其中的一个AddCommand

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();
}
复制代码

经过实例化AddCommand对象而且将他做为参数传递到Calculator#calculate方法当中用以调用计算方法:

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

3.4 规则引擎(rule engine)

当咱们最终编写了大量的嵌套if语句时,每个条件都描述了特定的业务规则,用于评估正确逻辑操做的执行。规则引擎将这些复杂的草从主代码中去掉。规则引擎是用于评估规则而且基于输入返回结果

让咱们经过设计一个简单的规则引擎来作下试验。这个引擎是经过一组规则来处理表达式,并从选中的规则返回结果。首先,咱们定义一个规则接口:

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();
    }
}
复制代码

这个规则引擎接收一个表达式而且返回Result。如今,咱们设计一个带有两个数值变量以及一个用于操做的Operator对象的表达式(Expression)类:

public class Expression {
    private Integer x;
    private Integer y;
    private Operator operator;        
}
复制代码

最后,咱们定义一个AddRule类,它只在操做中使用到:

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;
    }    
}
复制代码

如今,咱们可以使用Expression来调用RuleEngine了:

@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());
}
复制代码

4. 总结

在此次教程中,咱们探索了一系列不一样的方法来简化复杂的代码。同时咱们也学到了这么去使用有效的设计模式来取代繁杂的嵌套fi声明语句。

一如既往,读者们能够在咱们的github仓库中获取到完整的源码。

咱们下期见。

5. 译者总结

想必你们之前或多或少都会被这种无止境的if语句所困扰,这篇文章中做者介绍了4种方法用来取代原先维护成本极高的if结构,但愿看了之后对你们以后的结构设计思路有所帮助,避免出现让别人叫惨的if地狱。


小喇叭

广州芦苇科技Java开发团队

芦苇科技-广州专业互联网软件服务公司

抓住每一处细节 ,创造每个美好

关注咱们的公众号,了解更多

想和咱们一块儿奋斗吗?lagou搜索“ 芦苇科技 ”或者投放简历到 server@talkmoney.cn 加入咱们吧

关注咱们,你的评论和点赞对咱们最大的支持

相关文章
相关标签/搜索