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
Refactoring if/else logic
提问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 userType
an 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 if
branch 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 userType
variable) into AdminUser
and StudentUser
(and possibly others) and use polymorphism.
仅基于变量名称,我猜测您应该将User
(或任何具有userType
变量的)子类化为AdminUser
和StudentUser
(可能还有其他)并使用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 Admin
and 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.
我对这段代码要做的第一件事是创建类型Admin
and 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 user
interface, Student
,Admin
interfaces the extends it and UsaStudent
,MexicoStudent
,UsaAdmin
,MexicoAdmin
implementation that do some stuff. Hold a User
instance and just call its doStuff
method.
使用 OOP 概念:这取决于设计的其余部分,但也许您应该有一个user
接口、Student
、Admin
接口扩展它和UsaStudent
、MexicoStudent
、UsaAdmin
、MexicoAdmin
实现做一些事情。持有一个User
实例并调用它的doStuff
方法。