重构if/else逻辑

Dav*_*vid 35 java refactoring if-statement

我有一个带有千行if/else逻辑方法的java类,如下所示:

if (userType == "admin") {
     if (age > 12) {
          if (location == "USA") {
               // do stuff
          } else if (location == "Mexico") {
               // do something slightly different than the US case
          }
     } else if (age < 12 && age > 4) {
          if (location == "USA") {
               // do something slightly different than the age > 12 US case
          } else if (location == "Mexico") {
               // do something slightly different
          }
     }
 } else if (userType == "student") {
     if (age > 12) {
          if (location == "USA") {
               // do stuff
          } else if (location == "Mexico") {
               // do something slightly different than the US case
          }
     } else if (age < 12 && age > 4) {
          if (location == "USA") {
               // do something slightly different than the age > 12 US case
          } else if (location == "Mexico") {
               // do something slightly different
          }
     }
Run Code Online (Sandbox Code Playgroud)

我应该如何将其重构为更易于管理的内容?

Pét*_*rök 26

您应该使用可能在枚举中实现的策略,例如:

enum UserType {
  ADMIN() {
    public void doStuff() {
      // do stuff the Admin way
    }
  },
  STUDENT {
    public void doStuff() {
      // do stuff the Student way
    }
  };

  public abstract void doStuff();
}
Run Code Online (Sandbox Code Playgroud)

由于代码中每个最外层if分支中的代码结构看起来几乎相同,因此在下一步重构中,您可能希望使用模板方法分解该重复.或者,您也可以将位置(可能还有年龄)转换为策略.

更新:在Java4中,您可以手动实现类型安全枚举,并使用普通的旧子类来实现不同的策略.


Bil*_*ard 12

我要对这段代码做的第一件事是创建类型,Admin并且Student两者都继承自基类型User.这些类应该有一个doStuff()隐藏此逻辑其余部分的方法.

根据经验,只要你发现自己打开类型,就可以使用多态.


duf*_*ymo 9

成千上万的?也许你需要一个规则引擎.Drools可能是一个可行的选择.

或者一个命令模式,它封装了每个案例的所有"做一些稍微不同"的逻辑.将每个命令存储在地图中,并将年龄,位置和其他因素作为关键字连接起来.查找命令,执行它,你就完成了.干净整洁.

Map可以存储为配置并在启动时读入.您可以通过添加新类和重新配置来添加新逻辑.


And*_*s_D 6

首先 - 使用userType和location的枚举 - 然后你可以使用switch语句(提高可读性)

第二 - 使用更多方法.

例:

switch (userType) {
  case Admin: handleAdmin(); break;
  case Student: handleStudent(); break;
}
Run Code Online (Sandbox Code Playgroud)

然后

private void handleAdmin() {
  switch (location) {
    case USA: handleAdminInUSA(); break;
    case Mexico: handleAdminInMexico(); break;
  }
}
Run Code Online (Sandbox Code Playgroud)

此外,识别重复的代码并将其放入额外的方法中.

编辑

如果有人强迫您在没有枚举的情况下编写Java代码(就像您被迫使用Java 1.4.2一样),请使用'final static'而不是enums或执行以下操作:

  if (isAdmin(userType)) {
    handleAdmin(location, age);
  } else if (isStudent(userType)) {
    handleStudent(location, age));
  }

//...

private void handleAdmin(String location, int age) {
  if (isUSA(location)) {
    handleAdminInUSA(age);
  } else if (isUSA(location)) {
    handleAdminInMexico(age);
  }
}

//...

private void handleAdminInUSA(int age) {
  if (isOldEnough(age)) {
    handleAdminInUSAOldEnough();
  } else if (isChild(age)) {
    handleChildishAdminInUSA(); // ;-)
  } //...
}
Run Code Online (Sandbox Code Playgroud)


Syn*_*tic 1

您可以创建userType一个enum,并为其提供一个执行所有“做一些稍微不同”操作的方法。