Java 重构 if/else 逻辑

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2913495/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 14:26:17  来源:igfitidea点击:

Refactoring if/else logic

javarefactoringif-statement

提问by David

I have a java class with a thousand line method of if/else logic like this:

我有一个带有一千行 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
          }
     }

How should I refactor this into something more managable?

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

回答by Syntactic

You could make userTypean enum, and give it a method that performs all of your "do something slightly different" actions.

你可以制作userType一个enum,并给它一个方法来执行你所有的“做一些稍微不同的”动作。

回答by Péter T?r?k

You should use Strategies, possibly implemented within an enum, e.g.:

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

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

  public abstract void doStuff();
}

As the code structure within each outermost ifbranch in your code looks pretty much the same, in the next step of refactoring you might want to factor out that duplication using template methods. Alternatively, you might turn Location (and possibly Age) into a strategy as well.

由于您的代码中每个最外层if分支中的代码结构看起来几乎相同,因此在重构的下一步中,您可能希望使用模板方法来排除重复。或者,您也可以将位置(也可能是年龄)变成一种策略。

Update:in Java4, you can implement a typesafe enumby hand, and use plain old subclassing to implement the different strategies.

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

回答by Peter

without more information there is no good answer

没有更多信息就没有好的答案

but fair guess would be this: use OO

但公平的猜测是:使用 OO

first define a User, define Admin, Student and all other types of users and then let polymorphism take care of the rest

首先定义一个 User,定义 Admin、Student 和所有其他类型的用户,然后让多态来处理剩下的事情

回答by Hank Gay

Based just on the variable names, I'm guessing that you should subclass User(or whatever it is that has a userTypevariable) into AdminUserand StudentUser(and possibly others) and use polymorphism.

仅基于变量名称,我猜测您应该将User(或任何具有userType变量的)子类化为AdminUserStudentUser(可能还有其他)并使用polymorphism

回答by Andreas Dolk

First - use enums for userType and location - then you can use switch statements (improves readability)

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

Second - use more methods.

第二 - 使用更多的方法。

Example:

例子:

switch (userType) {
  case Admin: handleAdmin(); break;
  case Student: handleStudent(); break;
}

and later

然后

private void handleAdmin() {
  switch (location) {
    case USA: handleAdminInUSA(); break;
    case Mexico: handleAdminInMexico(); break;
  }
}

Further, identify duplicate code and put it in extra methods.

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

EDIT

编辑

If someone forces you to code Java without enums (like you're forced to use Java 1.4.2), use 'final static's instead of enums or do something like:

如果有人强迫您在没有枚举的情况下编写 Java(就像您被迫使用 Java 1.4.2),请使用“最终静态”而不是枚举或执行以下操作:

  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(); // ;-)
  } //...
}

回答by Uri

The risk of this is not just that it is unsightly, but that it is very error prone. After a while, you could run into a risk of overlaps in your conditions.

这样做的风险不仅在于它不美观,而且很容易出错。一段时间后,您可能会遇到条件重叠的风险。

If you can really distinguish the condition by user type, you can at the minimum break the body of each condition into a separate function. So that you check based on the type, and call an appropriate function specific to that type. A more OO solution is to represent each user as a class, and then override some calculation method to return a value based on the age. If you can't use classes but can at least use enums, then you will be able to do a nicer switch statement on the enums. Switches on Strings will only come in Java 7.

如果你真的可以通过用户类型来区分条件,你至少可以将每个条件的主体分解为一个单独的函数。这样您就可以根据类型进行检查,并调用特定于该类型的适当函数。更面向对象的解决方案是将每个用户表示为一个类,然后覆盖一些计算方法以根据年龄返回一个值。如果您不能使用类但至少可以使用枚举,那么您将能够对枚举执行更好的 switch 语句。字符串上的开关只会出现在 Java 7 中。

What worries me is situations of overlaps (e.g., two user types with some shared rules, etc.). If that ends up being the case, you might be better off representing the data as some external file (E.g., a table) which you would read and maintain, and your code will essentially operate as a driver that does the appropriate lookup in this data set. This is a common approach for complex business rules, since nobody wants to go and maintain tons of code.

我担心的是重叠的情况(例如,具有某些共享规则的两种用户类型等)。如果情况确实如此,您最好将数据表示为一些您将读取和维护的外部文件(例如,表),并且您的代码本质上将作为驱动程序在此数据中进行适当的查找放。这是复杂业务规则的常用方法,因为没有人愿意去维护大量代码。

回答by Bill the Lizard

The first thing I would do with this code is create the types Adminand Student, both of which inherit from the base type User. These classes should have a doStuff()method where you hide the rest of this logic.

我对这段代码要做的第一件事是创建类型Adminand Student,它们都继承自基本类型User。这些类应该有一个doStuff()方法,您可以在其中隐藏此逻辑的其余部分。

As a rule of thumb, any time you catch yourself switching on type, you can use polymorphism instead.

根据经验,任何时候当你发现自己在切换类型时,你都可以使用多态来代替。

回答by tkr

I would probably first check whether you can parametrize the code doStuff and doSimilarStuff.

我可能会首先检查您是否可以对代码 doStuff 和 doSimilarStuff 进行参数化。

回答by duffymo

Thousands? Maybe a rules engine is what you need. Drools could be a viable alternative.

几千?也许你需要一个规则引擎。Drools 可能是一个可行的选择。

Or a Command pattern that encapsulates all the "do something slightly different" logic for each case. Store each Command in a Map with the concatentation of age, location, and other factors as the key. Lookup the Command, execute it, and you're done. Nice and clean.

或者一个命令模式,它封装了每个案例的所有“做一些稍微不同的事情”的逻辑。将每个 Command 存储在 Map 中,以年龄、位置和其他因素的串联为键。查找命令,执行它,你就完成了。漂亮干净。

The Map can be stored as configuration and read in on start up. You can add new logic by adding new classes and reconfiguring.

地图可以存储为配置并在启动时读取。您可以通过添加新类和重新配置来添加新逻辑。

回答by Amir Rachum

Use OOP Concepts: This is dependent of the rest of the design, but maybe you should have a userinterface, Student,Admininterfaces the extends it and UsaStudent,MexicoStudent,UsaAdmin,MexicoAdminimplementation that do some stuff. Hold a Userinstance and just call its doStuffmethod.

使用 OOP 概念:这取决于设计的其余部分,但也许您应该有一个user接口、StudentAdmin接口扩展它和UsaStudentMexicoStudentUsaAdminMexicoAdmin实现做一些事情。持有一个User实例并调用它的doStuff方法。