目前必须创建一个基于不同对象的决策表,每个对象可以有不同的/多个信息。
示例:
object A can be: OK / KO
object B can be: OK / WARNING / KO
object C can be: STARTING / RUNNING / ENDING
根据A,B和C的状态,我们得到不同的输出。我目前正在做很多IF语句,感觉它是非常新手的编码。
像-这样:
if (C == STARTED) {
if (A == OK) {
if (B == OK)
return "something";
if (B == WARNING)
return "something else";
else
return "something more";
}
...
}
是否有任何已知的技术(使用已在Java 8中使用的哈希或其他东西)以正确的方式处理这类问题?
考虑实现决策树,但我当前的if语句需要大约30行,并且不确定创建(一堆)全新类来解决这个问题是否明智。
答案 0 :(得分:1)
事实上,你有三个不同的案例:
if (C == STARTED) {
if (A == OK) {
if (B == OK)
return "something";
if (B == WARNING)
return "something else";
else
return "something more";
}
...
}
将不同方法中的不同案例或类中的每个案例分开,允许对其进行单一测试,以便轻松理解每个规则并对其进行更改而不会对其他规则产生副作用。
例如:
if (C == STARTED && (A == OK) && (B == OK)
是一条规则
if (C == STARTED && (A == OK) && (B == WARNING)
是另一条规则
if (C == STARTED && (A == OK) && (B == KO)
是另一条规则
为每个方法创建一个方法或使用处理方法创建一个接口,并使每个规则成为它的独特实现。
责任链是这种方式的良好模式。
例如,您可以拥有这些。
规则界面:
public interface IRule {
public void setNextRule(IRule nextRule);
public abstract boolean apply(Data data);
}
规则界面的抽象公共类:
public abstract class AbstractRule implements IRule {
protected IRule nextRule;
public void setNextRule(IRule nextRule) {
this.nextRule = nextRule;
}
public boolean applyNextRuleIfExist(Data data) {
if (this.nextRule != null) {
return this.nextRule.apply(data);
}
return false;
}
}
具体规则:
public class RuleXXX extends AbstractRule {
public boolean apply(Data data) {
if (data.C == STARTED && (data.A == OK) && (data.B == OK){
return true;
}
return applyNextRuleIfExist(inputDataForDiscountRules);
}
}
最后,您可以创建规则链并使用它:
IRule firstRule = new RuleXXX();
firstRule.setNextRule(new RuleYYY());
...
// apply the chain
Data data = ...;
firstRule.apply(data);
答案 1 :(得分:1)
有很多方法。如果这些状态是枚举值,整数或字符串,那么开关看起来比许多嵌套的if
看起来更清晰,虽然它归结为相同的东西,但最终仍然会有一些深度嵌套。
switch (C) {
case STARTED :
{
// do stuff for this state
}
case RUNNING :
{
// do stuff for this state
}
}
请勿在必要时忘记break;
陈述,否则案件可能会失败。但是,在返回声明之后没有必要。
进一步的方法是简单地在方法中解决问题。
switch (C) {
case STARTED : return handleStartedState(A, B);
case RUNNING : return handleRunningState(A, B);
}
然后,您可以在单独的方法中实现每个C
个案的逻辑,而这个方法对其他输入也是如此。这样做的缺点是你可能会得到许多方法,这些方法的长名称用于各种输入组合。
更好的面向对象方法可能是如何处理类本身中各种状态组合的责任。我不知道您的A
,B
和C
是什么,但如果它们是您控制的类,则可以根据需要在每个代理中创建方法。例如,C
类的方法handle(A, B)
根据其自身状态调用A
上的方法,然后A
对B
执行相同操作。解决这个问题的方法是使用the state pattern,这是一种将行为与某个对象的状态耦合的设计模式。
这确实意味着你只是为了处理这个问题而创建了一些类,而且可能过于复杂,而不是需要那么复杂。问自己这些问题:
如果其中任何一个属实,您可以考虑采用更复杂的方法。但是,如果几十行if
语句完成这项工作就好了,它们不太可能很快改变,变化不是重构的噩梦,也许它们是适合这项工作的工具。虽然我非常重视前期设计并着眼未来,但很容易被设计为一种过于通用的设计,并且当自行车足够时最终成为火箭飞船。换句话说,避免being an "architecture astronaut"。一个众所周知的开发规则是始终从最简单的事情开始。我认为这不是绝对的;如果问题开始扩大,当一些前期设计从一开始就是理想的时候,重构会变得困难。但通常这是一个很好的初始方法。
同时也意识到模式可以提供答案,但它们本身就是通过环境优雅而存在的:面向对象的编程。 Java是kingdom of nouns, of "things", when sometimes what you need are verbs, "actions"。函数式编程允许一些需要面向对象模式的东西自然地完成,你甚至没有意识到它有一个模式。 Java 8向功能编程迈出了重要的一步,因此您可能希望研究如何链接行为而不是类。
最后,对于易于扩展或更改的复杂规则集,您需要查看规则引擎。正如freedev在评论中指出的那样,Drools is a Java solution for this。
问题没有“一刀切”的答案,因为它过分依赖于项目,上下文,代码库的其余部分......所以希望上面的信息可以帮助您找到最有效的方法。< / p>