一直困扰我的问题,得到了缓解,主要是受到了JBoss Rules的启发。在经过了十几分钟疯狂的编程(就像周杰伦在不能说的秘密里斗琴的场景一样)之后,我终于完成了我想要的东西,几行测试代码,呈现绿条的 JUnit。沉郁多日小步前行,今天是我最近最爽的一次编程了。
public void testExecuteWorkingSpace() throws ClassNotFoundException{
RuleExpression ruleExpression= generateRuleExpression();
Stockpiling sri = new StockpilingRecordItem("01", 2500, 18);
ShipCapacity sc=new ShipCapacity(4000);
WorkingSpace ws=new WorkingSpace();
ws.bindingRuleWithFact(ShipCapacityCEI.class, ShipCapacity.class);
ws.bindingRuleWithFact(StockpilingDayIntervalCEI.class,
StockpilingRecordItem.class);
ws.setRuleExpression(ruleExpression);
ws.addFact(sri);
ws.addFact(sc);
assertTrue(ws.execute());
}
由于一个结果可能由多个条件限度得出,比如堆存费,我可以从StockpilingRecordItem中获得Days和Stact,来区分专堆
SpecialStackCEI和时间段StockpilingDayIntervalCEI这两个规则,我直接调用
conditionExpression.matching,并且传入StockpilingRecordItem对象即可。但是如果我再加一个,整船配
载量(ShipCapacity)影响费率,那怎么办?我总不能加一个条件,就给StockpilingRecordItem对象加一个属性吧。这显然又
要传入多个类似于StockpilingRecordItem的对象。然后我的规则引擎就能自动的判断哪个对象需要跟哪个规则进行matching,这样
各个规则对象的matching方法就会向下转型了。
好吧,我好像需要一个对象来做这件事,受到JBoss Rules的启发,我叫它WorkingSpace。
public void bindingRuleWithFact(Class condition, Class fact) ;
public void addFact(Object object) ;
public boolean execute();
先是要将条件表达式项和事实绑定(我之前都以非正式的语气称号它为事实,但是JBoss
Rules也这么称呼它,并且也以JavaBean的形式来表示事实,这使得我更加自信的去使用。于是我又加了个pacage叫facts,哦,那
StockpilingRecord可以将事实的生成服务,或者策略之类的了。这也让我对获得整船配载量的方法应该写在什么地方的问题不在疑惑,它只是一
个生成事实的服务类)。
然后我可以添加事实。比如
Stockpiling sri = new StockpilingRecordItem("01", 2500, 18);
ShipCapacity sc=new ShipCapacity(4000);
这样的事实对象。它们都是普通的JavaBean。过去我还在为它们是普通的JavaBean而感到羞愧,可是现在它们也变得名正言顺了。
这样,我就可以执行(execute)了。执行实际上只是,来判断我的条件都成立。
这与JBoss Rules比起来还有很大的差距。
它的WorkMemory直接读取规则定义文件:
when o:Order-->getQuantity>50
then
它的规则文件里直接将If then都搞定了。而我这里只能判断出if是否成立,之后的处理我还是写在计算策略(如StockpilingFeeCalculateStrategy)里。比如:
if (ce.matching(stockpilingRecordItem)) {
int matchingDays=calculateMatchingDays();
Rate rate=calculateRate();
int quantity=calculateQuantity();
charges = new StockpilingCharges(rate, quantity, matchingDays);
System.out.println(charges.total().getValue());
}
但实际上,我或许可以继续模仿JBoss Rules,将if成立的执行块中的代码extract成一个方法,然后在Move到一个新的Service中,最后将其写入到规则表达式的结果表达式中。
另外,JBoss Rules将规则是什么都写在规则文件里,而我写在了条件表达式项(比如StockpilingDayIntervalCEI)中。当我打算将这些写到文本文件里时,我想我会选择使用JBoss Rules,而现在我只打算参考它。
本来ShipCapacityCEI(我将条件表达式项都加了个CEI的后缀,是ConditionExpressionItem的缩写)是为计算免堆期准备的规则,可是现在我也可以把它加到判定费率的条件表达式里了。
在此,我再一次怀疑我的ConditionExpression使用了组合模式是否多余,我还来不及仔细分析它。
问题:
我可以在制定合同时做好规则和事实的映射。
但是,我怎么才能在计算时,让系统知道它需要哪些事实?