Java-复杂决策表

Java-复杂决策表,java,Java,目前必须创建一个基于不同对象的决策表,每个对象可以有不同/多个信息 例如: 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 =

目前必须创建一个基于不同对象的决策表,每个对象可以有不同/多个信息

例如:

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";
    }
  ...
}
是否有任何已知的技术(使用hasmaps或Java8中已有的东西)能够以正确的方式处理此类问题


考虑过实现一个决策树,但我当前的if语句大约需要30行,不确定创建一个(一堆)全新类来解决这个问题是否明智。

事实上,这里有三种不同的情况:

if (C == STARTED) {
    if (A == OK) {
        if (B == OK)
            return "something";
        if (B == WARNING)
            return "something else";
        else
            return "something more";
    }
  ...
}
不同方法中的不同案例或类中的每一个案例都允许对其进行统一测试,以便轻松理解每一条规则并对其进行更改,而不会对其他规则产生副作用。

例如:

如果(C==STARTED&&(A==OK)&(B==OK)
是一条规则

如果(C==STARTED&&(A==OK)&&(B==WARNING)
是另一条规则

如果(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);     
    }          
}
规则接口的抽象公共类:

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);     
    }          
}
具体规则:

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);

有很多方法。如果这些状态是枚举值、整数或字符串,则开关看起来比许多嵌套的
If
s要干净一些,尽管它归结为同一件事,并且最终可能会有一些深层嵌套

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
类有一个方法
句柄(a,B)
,该方法根据自身的状态调用
a
上的方法,
a
然后对
B
执行相同的操作。实现这一点的方法是使用一种将行为与某个对象的状态相耦合的设计模式

这确实意味着您正在创建一些类来处理这个问题,而这可能会使一些根本不需要变得如此复杂的事情变得过于复杂。问问自己以下问题:

  • 将来有可能增加更多的案件来处理吗
  • 增加更多案例是否经常发生
  • 是否有可能以动态的方式扩展功能(可能是通过客户端使用代码)
  • 新案例的增加会导致代码长度呈指数增长,而不是线性增长吗
如果有一个是真的,你可以考虑一个更复杂的方法。但是如果有几十行的<代码>如果语句的话,这项工作就很好,而且它们不太可能马上改变,而且改变不是重构噩梦,也许它们是正确的工具。虽然我重视前面的设计,展望未来,但这很容易。o被诱骗进入一个过于通用的设计,最终成为一个火箭飞船,当一辆自行车已经足够。换句话说,一个众所周知的发展规则是总是从最简单的事情开始,可能是不可能的。我不认为它是绝对的;如果一个问题开始扩展,重构就变得困难了。因此,一些预先设计从一开始就可能是理想的。但通常这是一个很好的初始方法

也要意识到模式可以提供一个答案,但它们自身的存在得益于它们的环境:面向对象编程。Java是最重要的。函数式编程允许一些需要面向对象模式的事情自然地完成,以至于你甚至没有意识到它有一个模式。Java 8已经占据了重要地位t迈向函数式编程,因此您可能希望了解如何链接行为而不是类

最后,对于倾向于扩展或更改的复杂规则集,您需要查看规则引擎


这个问题没有“一刀切”的答案,因为它太依赖于项目、上下文和代码库的其他部分……所以希望以上信息能帮助您找到最有效的方法。

查看可能的命令模式副本?或者查看