我试图根据某些计算或条件逻辑将值从一个枚举映射到另一个枚举,而这些逻辑需要为类变量设置正确的枚举值。如何在不使用太多if / else switch语句的情况下做到这一点?
Enum BRAND {
MINI, FERRARI, PAGANI
}
和另一个枚举
Enum ENGINE {
LEVEL1, LEVEL2, LEVEL3
}
我有一个像:
Class Car() {
int model;
int year;
Engine engine;
// I want to calculate set the engine depending on the brand based on conditional logic
public carEngineCalculator (Brand b) {
Car mycar = new Car();
if (mycar.isSuperCar(b) {
if (mycar.isCrazyGood(b)) {
mycar.engine = ENGINE.LEVEL1;
} else {
mycar.engine = ENGINE.LEVEL2;
}
} else {
mycar.engine = ENGINE.LEVEL3;
}
... //And the conditions can be more complex
}
public boolean isSuperCar(Brand b) {
if (b.FERRARI || b.PAGANI) {
return true;
}
return false;
}
public boolean isCrazyGood(Brand b) {
return ...;
}
}
为了设置这些值,可能需要检查多个以上的条件,并且我想避免上述讨厌的if / else / switch语句。有没有更实用的方法可以做到这一点?
答案 0 :(得分:3)
首先,将isSuperCar
和isCrazyGood
方法移到Brand
中,而不要让它们使用Brand
参数。您可以类似地向Engine
添加一个静态工厂方法,该方法封装了您尝试编码的逻辑。但这并不能完全避免“讨厌的if / else / switch语句”,但是它可能更具可读性。
例如:
public Car(Brand b) {
this.engine = Engine.forBrand(b);
}
然后:
enum Engine {
LEVEL1, LEVEL2, LEVEL3
public static Engine forBrand(Brand b) {
if (b.isSuperCar()) {
return b.isCrazyGood() ? LEVEL1 : LEVEL2;
}
return LEVEL3;
}
}
还请注意,您的isSuperCar
方法可以简单地是:
return b.equals(Brand.FERRARI) || b.equals(Brand.PAGANI);
无需编写if (...) return true; else return false;
或类似内容-只需直接在if
语句中使用布尔表达式即可。
答案 1 :(得分:3)
如果品牌和引擎的映射是一对一的,则可以执行以下操作:
enum Brand {
MINI(Engine.LEVEL1),
FERRARI(Engine.LEVEL2),
PAGANI(Engine.LEVEL3);
private final Engine engine;
private Brand(Engine engine) {
this.engine = engine;
}
public final Engine getEngine() {
return engine;
}
}
另一个选择:
enum Brand {
MINI(false, false),
FERRARI(true, true),
PAGANI(false, true);
private final boolean superCar;
private final boolean crazyGood;
private Brand(boolean superCar, boolean crazyGood) {
this.superCar = superCar;
this.crazyGood = crazyGood;
}
public final Engine getEngine() {
if (superCar) {
return (crazyGood) ? Engine.LEVEL1 : Engine.LEVEL2;
}
return Engine.LEVEL3;
}
}
如果映射不是一对一的,并且您需要基于某些参数以某种方式动态计算引擎,则也可以使用以下方法:
enum Brand {
MINI {
@Override
public Engine getEngine(boolean superCar, boolean crazyGood) {
return (superCar && crazyGood) ? Engine.LEVEL1 : Engine.LEVEL2;
}
},
FERRARI {
@Override
public Engine getEngine(boolean superCar, boolean crazyGood) {
return superCar ? Engine.LEVEL1 : Engine.LEVEL3;
}
},
PAGANI {
@Override
public Engine getEngine(boolean superCar, boolean crazyGood) {
return Engine.LEVEL3;
}
};
public abstract Engine getEngine(boolean superCar, boolean crazyGood);
}
或者类似这样的东西,您有一些默认值并且仅在特殊情况下可以覆盖:
enum Brand {
MINI,
FERRARI {
@Override
public Engine getEngine(boolean superCar, boolean crazyGood) {
return superCar ? Engine.LEVEL1 : Engine.LEVEL3;
}
},
PAGANI;
public Engine getEngine(boolean superCar, boolean crazyGood) {
return Engine.LEVEL3;
}
}
使用枚举有很多可能,实际上我更喜欢复杂的if / else或switch语句。当然,这取决于您要确切执行的操作,并且由于没有提供太多信息,因此我无法给出最佳答案。希望对您有帮助。
答案 2 :(得分:3)
使用我所说的谓词看起来像这样:
public enum Brand {
MINI,
FERRARI,
PAGANI
}
public enum Engine {
LEVEL1,
LEVEL2,
LEVEL3
}
public class Entry {
public final Predicate<Car> pred;
public final Engine engine;
public Entry(Predicate<Car> pred, Engine engine) {
this.pred = pred;
this.engine = engine;
}
}
public class Car {
int model;
int year;
Engine engine;
public void carEngineCalculator(Brand b) {
Car mycar = new Car();
List<Entry> cases = new ArrayList<>();
cases.add(new Entry(c -> c.isSuperCar(b) && c.isCrazyGood(b), Engine.LEVEL1));
cases.add(new Entry(c -> c.isSuperCar(b) && !c.isCrazyGood(b), Engine.LEVEL2));
cases.add(new Entry(c -> !c.isSuperCar(b), Engine.LEVEL3));
mycar.engine = cases.stream().filter(x -> x.pred.test(mycar)).findFirst().get().engine;
}
public boolean isSuperCar(Brand b) {
if ((b == Brand.FERRARI) || (b == Brand.PAGANI)) {
return true;
}
return false;
}
public boolean isCrazyGood(Brand b) {
return false;
}
}
您创建一个包含谓词和结果的列表,并使用流,过滤器和findFirst遍历列表并找到正确的结果。如果条件比您简单,则不需要谓词并对其进行一些测试。
答案 3 :(得分:0)
我可能会将品牌存储在Car
类中,但这是另一个问题。我将在Car
类中有一个静态映射,用于跟踪每个品牌使用的引擎(如Ralf Renz所建议的那样):
Class Car {
int model;
int year;
Engine engine;
static Map<Brand, Engine> carEngineMap = new HashMap<>();
public static void setBrandEngine(Brand b, Engine e) {
carEngineMap.put(b, e);
}
// I want to calculate set the engine depending on the brand based on conditional logic
public carEngineCalculator (Brand b) {
Car mycar = new Car();
mycar.engine = carEngineMap.get(b);
}
public boolean isSuperCar(Brand b) {
if (b.FERRARI || b.PAGANI) {
return true;
}
return false;
}
public boolean isCrazyGood(Brand b) {
return ...;
}
}
然后您将每个品牌的条件分别放入,例如
Car.setBrandEngine(Brand.FERRARI, Engine.LEVEL2);
Car.setBrandEngine(Brand.PAGANI, Engine.LEVEL1);
...
答案 4 :(得分:-1)
使用谓词,条件(品牌,引擎,条件)创建枚举,并在其中提供条件。之后:
Conditions.values().foreach(condition -> {
condition.isApplicable(variblesDto) ? return condition.apply() : continue;
});
,您可以在需要新条件时随时更新Enum。它也会按照Enum的顺序进行,因此您可以使用它