如何处理 Java 中的多个退出点

How to handle multiple exit points in Java

有时我会遇到一个例程,该例程将测试某些条件并继续或退出,类似于以下代码:

public void execute() {
    if (context.condition1()) {
        LOGGER.info("Condition 1 not satisfied.");
        return;
    }
    doSomeStuff();

    if (context.condition2()) {
        LOGGER.info("Condition 2 not satisfied.");
        return;
    }
    if (context.condition3()) {
        LOGGER.info("Condition 3 not satisfied.");
        return;
    }

    doRestOfStuff();
}

假设在进入此方法之前无法测试这些条件。也许这是一个带有单一入口点的 servlet 或控制器。根据我的经验(远非广泛),这似乎是一种普遍情况。

现在,这段代码不太好闻,是吗?处理此问题的最佳策略是什么?

这是我到目前为止的想法:

public void execute() {
    checkCondition1AndExecute();
}

private void checkCondition1AndExecute() {
    if (context.notCondition1()) {
        doSomeStuff();
        checkCondition2AndExecute();
    } else {
        LOGGER.info("Condition 1 not satisfied.");
    }
}

private void checkCondition2AndExecute() {
    if (context.notCondition2()) {
        checkCondition3AndExecute();
    } else {
        LOGGER.info("Condition 2 not satisfied.");
    }
}

private void checkCondition3AndExecute() {
    if (context.notCondition3()) {
        doRestOfStuff();
    } else {
        LOGGER.info("Condition 3 not satisfied.");
    }
}

它看起来不太好,但对我来说确实闻起来更好。我没有使用具有多个出口的大方法,而是使用小方法,每个方法负责一个特定条件(和出口点)。此外,它摆脱了愚蠢的 return; 行。

但是,我仍然想知道是否有一种模式或更好的策略来处理这个问题。

尝试阅读 switch 语句,它是多种语言的解决方案,特别是 java:

https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html

我们在谈论多少个不同的退出点?

如果像您的示例中那样只有 3 个,那么您的原始代码就可以了。它很容易阅读。我会将 "only have one exit point" 视为一般指导方针,而不是硬性规定。

将其更改为 if / else if 块的嵌套组我发现更难阅读,尤其是在缩进之后。如果您将来必须添加更多条件检查,您还 运行 有忘记将新条件正确放置到链中的风险。

但是,如果您有很多条件并且可能需要添加更多条件(可能在 运行 时),那么您可以利用 Chain of Responsibility 模式。

最终结果看起来像这样:

public void execute() {
    List<Condition> conditionChains = ....

    for(Condition condition : conditionChain){
          if(condition.notSatisfied(context)){
               //here use condition#toString() to explain what wasn't satisfied. 
               //Could use another method like getDescrption() instead...
               LOGGER.info(condition + " not satisfied.");
              return;
          }
          condition.execute(context);
    }
}

你会有一个接口 Condition,它有 2 个方法来检查可满足性,然后另一个方法来执行任何相关代码。

示例实现:

class Condition1 implements Condition{

    public boolean isSatisfied(Context context){
       ...
    }

    public void execute(Context context){
        doSomeStuff();
    }
}


class Condition2 implements Condition{

    public boolean isSatisfied(Context context){
       ...
    }

    public void execute(Context context){
       //do nothing
    }
}


class Condition3 implements Condition{

    public boolean isSatisfied(Context context){
       return !context.notCondition3();
    }

    public void execute(Context context){
        doRestOfStuff();
    }
}