替换嵌套 if 语句的设计模式(箭头反模式)

Nik*_*ola 7 oop design-patterns if-statement nested chain-of-responsibility

我注意到我的代码看起来很丑,而且很难维护。基本上我需要对某人进行检查。伪代码是这样的(顺便说一句,我无法在查询中“剪切”任何内容,这并不是我的问题的重点):

List<Person> persons = getPersonsBySomeQuery();

if (checkAnyPersonExists(persons)) {
  if (atLeastOneWithGivenNameExist(persons)) {
    if (noOneWithOtherNameExists(persons)) {
      filteredPersons = filterPersonsWithGivenName(persons);
      if (singleName(filteredPersons)) {
        // single person found
        if (someParameterFromQueryIsTrue) {
          if (someComplicatedLogicIsOK) {
            // found exactly one person, all OK!!!
          } else {
            // found exatcly one person with given name, but not OK
          }
        } else {
           // found exactly one person but parameter from query is not OK
        }
      } else {
        // found only persons with given name, but more then one
      }
    } else {
      // found person(s) with given name, but also some with different name
    }
  } else {
    // found person(s), all have different name
  }
} else {
  // noone found
}
Run Code Online (Sandbox Code Playgroud)

所以我在设计模式方面没有太多经验,但我阅读了它们,我开始认为我可以实现责任链模式。就像,每个 if-else 都可以是链中的一个元素,而且第 6 行的这个过滤器元素也可以是“可链接的”。

最后它可能看起来像:

AbstractChainElement getCheckChain() {
   return new CheckAnyExist(
          new CheckOneWIthGivenNameExist(
          new CheckNoOneWithOtherNameExist(
          new FilterOnlyGivenName(
          new CheckIsSingleName(
          new CheckOtherParameters(
          new CheckWithSomeComplicatedLogic()))))));          
}

getCheckChain().doChain(persons);
Run Code Online (Sandbox Code Playgroud)

你认为这是做这件事的好方法还是有什么更优雅的方法?

有了这个,我也可以使用工厂甚至抽象工厂模式构建用于检查不同检查类型的链。

就像是:

FactoryCheckThesePersonsByTheseParameters implements AbstractFactory {

     List<Person> getPersons() {
       // get persons with THIS query
     }

     AbstractChainElement getCheckChain() {
       // check persons THIS way
     }
}

FactoryCheckThatPersonsByThatParameters implements AbstractFactory {

     List<Person> getPersonsBySomeParameters() {
       // get persons with THAT query
     }

     AbstractChainElement getCheckChain() {
       // check persons THAT way
     }
}
Run Code Online (Sandbox Code Playgroud)

小智 2

这与设计模式无关,而是编码风格和优化。

您可以将条件组合为一个。即这个:

if (checkAnyPersonExists(persons)) {
  if (atLeastOneWithGivenNameExist(persons)) {
    if (noOneWithOtherNameExists(persons) {
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

首先,这似乎是对同一主题/集合进行多次查询。如果您使用它来查询数据库,那么效率会很低。例如,您可以通过将条件组合到单个查询中来做得更好。

如果这不是对数据库进行查询,那么您可以直接获取具有给定名称的人数,并根据该数字您可以确定要做什么,而不是重复稍有变化的查询。

另一方面,使用模式并不总是绝对的最佳实践,因为它会增加开销。一个简单的 If 语句、switch-case 或带有 return 的 if-not 语句比调用另一个函数/方法更好,因为它更快。

我认为你需要更具体一些。

编辑:例如,如果您有类似于以下内容的内容:

if (i == 1) {
    // action 1
} else {
    if (i == 2) {
        // action 2
    } else {
        if (i == 3) {
            // action 3
        } else {
            // action 4
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以使用 switch 语句

switch (i) {
    case 1:
        // action 1
        break;
    case 2:
        // action 2
        break;
    case 3:
        // action 3
        break;
    default:
        // action 4
        break;
}
Run Code Online (Sandbox Code Playgroud)

另一个例子可能是,如果您有:

if (i == 1) {
    // a couple of sentences action
}
else if (x == 2) {
    // a couple of sentences action
}
else if (y == 3) {
    // a couple of sentences action
}

// no more cope beyond the if statements
Run Code Online (Sandbox Code Playgroud)

这可以重构为:

if (i == 1) {
    // a couple of sentences action
    return;
}

if (x == 2) {
    // a couple of sentences action
    return;
}
Run Code Online (Sandbox Code Playgroud)

等等

例如,如果您有另一种技术:

if(name.equals("abc")){
    do something
} else if(name.equals("xyz")){
    do something different
} else if(name.equals("mno")){
    do something different
} ......
.....
else{ 
   error
}
Run Code Online (Sandbox Code Playgroud)

最好使用 Map 将每个字符串(如果它是您验证的有限已知字符串集合)映射到特定处理程序。您还可以考虑将一些代码移至单独的方法中

我从 SO 的几页中获取了这些示例,因为正如您所见,这没有绝对的规则,这取决于代码本身。因此,您可以做的就是拥有一些分析工具来与您一起处理代码。我认为 JetBrain 的 IntelliJ IDEA 是一个优秀的 IDE,具有内置的很酷的功能。Eclipse 也有一些类似的功能,但没有那么多。无论如何,这都是需要练习的。