如何替换 If-else 块条件

How replace If-else block condition

在我的代码中,我有一个 if-else 块条件,如下所示:

public String method (Info info) {
    if (info.isSomeBooleanCondition) {
        return "someString";
    }
    else if (info.isSomeOtherCondition) {
        return "someOtherString";
    }
    else if (info.anotherCondition) {
        return "anotherStringAgain";
    }
    else if (lastCondition) {
        return "string ...";
    }
    else return "lastButNotLeastString";
}

每个条件分支 returns 一个字符串。

if-else语句难以阅读、测试和维护,如何替换? 我正在考虑使用责任链模式,在这种情况下是否正确? 有没有其他优雅的方式可以做到这一点?

我会简单地分解出 returns:

return
    info.isSomeBooleanCondition ? "someString" :
    info.isSomeOtherCondition   ? "someOtherString" :
    info.anotherCondition       ? "anotherStringAgain" :
    lastCondition               ? "string ..." :
    "lastButNotLeastString"
;

我只能假设您的代码不存在于 Info class 中,因为它是在除最后一个条件之外的所有引用中传递的。我的第一直觉是将 String OtherClass.method(Info) 变成 String Info.method() 并使其 return 成为合适的字符串。

接下来我要看一下条件。它们是真正的条件还是可以映射到 table。每当我看到执行查找的代码时,例如这样,我倾向于尝试将其放入字典或映射中,以便我可以执行查找值。

如果您遇到必须检查的条件,那么我会开始考虑 lambda、委托或自定义接口。可以轻松表示同一类型的一系列 if..then。接下来,您将收集它们并相应地执行。 IMO,这将使 if..then 组更加清晰。在这一点上更多的代码是次要的。

interface IInfoCheck 
{
    bool TryCheck(Info info, out string);
}

public OtherClass()
{ 
    // Setup checks
    CheckerCollection.add(new IInfoCheck{
        public String check(out result) {
           // check code 
        }
    });
}

public String method(Info info) {    
    foreach (IInfoCheck ic in CheckerCollection) 
    {
        String result = null;
        if (ic.TryCheck(out result))
        {
            return result;
        }
   }
}

从有关问题的有限信息和给出的代码来看,这看起来像是类型切换的情况。默认解决方案是为此使用继承:

class Info {
public abstract String method();
};

class BooleanCondition extends Info {
    public String method() {
         return "something";
};

class SomeOther extends Info {
    public String getString() {
         return "somethingElse";
};

在这种情况下有趣的模式是装饰器、策略和模板方法。责任链还有另一个重点。链中的每个元素都实现逻辑来处理一些命令。链接时,如果对象无法处理命令,则它会转发该命令。这实现了一个松散耦合的结构来处理不需要中央调度的命令。

如果根据条件计算字符串是一个操作,并且class从名称我猜它可能是一个表达式树,你应该看看访问者模式。

问题陈述不符合理想的责任链场景,因为它是 either/or 种类或条件,看起来 'chained' 但实际上是 'not'。原因 - 处理责任链模式中的所有链-links,而不管之前的 links 中发生了什么,即没有链-links 被跳过(尽管你可以配置哪个链 link 要处理,哪个不处理 - 但链的执行仍然 - link 不依赖于前一个链 - link 的结果)。但是,在这种 if-else-if* 场景中 - 一旦 if 语句条件匹配,就不会评估进一步的条件。

我想到了一个不用if-else就可以实现上述功能的替代设计,但它更长但同时更灵活。

假设我们有一个 FunctionalInterface IfElseReplacer,它将 'info' 作为输入并给出 'String' 输出。

public Interface IfElseReplacer(){
   public String executeCondition(Info);
}

然后可以将上述条件重新表述为 lambda 表达式,如下所示 -
“(信息信息)-> info.someCondition ?someString”
“(信息信息)-> info.anotherCondition?someOtherString” 等等... 然后我们需要一个 processConditons 方法来处理这些 Lambda——它可以是 ifElseReplacer 中的默认方法 -

default String processConditions(List<IfElseReplacer> ifElseReplacerList, Info info){
String strToReturn="lastButNotLeastString";
for(IfElseReplacer ifElseRep:ifElseReplacerList){
    strToReturn=ifElseRep.executeCondition(info);
    if(!"lastButNotLeastString".equals(strToReturn)){
         break;//if strToReturn's value changes i.e. executeCondition returns a String valueother than "lastButNotLeastString" then exit the for loop
    }
  return strToReturn;
}

现在剩下的是(我跳过了这个代码 - 如果你需要它请告诉我然后我也会写这个) - 从哪里需要检查 if-else 条件 -

  1. 如上所述创建一个 lambda 表达式数组,将它们分配给 IfElseReplacer 接口,同时将它们添加到 IfElseReplacer 类型的列表中。
  2. 将此列表连同 Info 实例一起传递给默认方法 processConditions()。
  3. 默认方法将 return 字符串值,我们将与问题陈述中给出的 if-else-if* 块的结果相同。