编写更好的规则 <o:p></o:p>
作者: Edson Tirelli <o:p></o:p>
我们所常见的一个问题是“我怎样编写更好的规则?”,或者类似的问题<o:p></o:p>
- 我做错了什么?我有如此多过程代码在规则中…<o:p></o:p>
- 我怎样调用一个特定的规则?(它来自于两类用户:使用反向推导的规则引擎或者习惯于使用过程代码)<o:p></o:p>
- 我如何在一个集合中遍历?<o:p></o:p>
- 我如果在LHS中执行一个操作?<o:p></o:p>
所有上面的问题暴露出对声明式编程的误解或缺少正向推论引擎知识。
免责声明:这里没有负面的评判。这只是一个知识体系,对于那些使用规则的人们,需要对此有更深入的研究。我们需要使它易于被人们所理解并了解声明式编程的原理。<o:p></o:p>
就像所说的那样,我们都知道编写规则是一个创造性的工作,不是说只有一条路来完成它。这里没有所谓对和错,只有说更好或更糟的方法。
<o:p></o:p>
因此我尝试给出一些提示关于如何通过一些症状判读你的规则中有一些不好的因素,以及怎样改进规则以去除这些症状。
<o:p></o:p>
症状
1. 太多的过程代码:
如果你的规则需要建立几个函数,或者推论部分过于复杂,它可能就是规则出现问题的信号。规则被认为是一种声明式描述模式,将在fact中查询并且当模式匹配后推论被认为是一系列顺序执行的动作。<o:p></o:p>
2. 在推论中有流控制结构:
如果你的规则在推论中包含流控制结构,比如if或switch,那很有可能你的规则有严重问题。循环结构如for和while可能在极少数情况下需要用到,但是他们通常也代表规则存在一定问题。<o:p></o:p>
3. 多余的eval():
用我的话来说:“Eval是魔鬼”。Eval是非常灵活的条件元素,但是它也是一个大问题。从开始用它,如果广泛的使用,你的规则将变得不可读。同样,因为你可以在Eval中做几乎任何事情,引擎无法对它做任何假设,因此也很难提供任何优化。在Drools3.0.X中,在某些情况下需要使用eval,但是从<st1:chmetcnv w:st="on" tcsc="0" unitname="m" sourcevalue="3.1" numbertype="1" negative="False" hasspace="False">3.1M</st1:chmetcnv>1以后,我们提供了很多语言表达式的很多改进,减少了很多需要使用eval的情况。因此如果你使用了许多eval表达式,那可能可以对此进行改进。<o:p></o:p>
如何改进规则
1. 业务领域建模:
可能你需要担心的最重要一点是怎样表现你的业务领域模型。一个简单的类推是将它与数据模型和RDMS系统相比较:我们都知道性能、简易性和SQL查询的效率是直接依赖于数据模型的质量。同样的原因,规则的性能、简易性和规则的效率直接依赖于业务模型的质量。不同的规则引擎对业务模型有不同的表现方式,但是根本上来说,你的业务模型将是你的业务本体的实现。从另一方面来说,你知道你的业务是什么,它运行的需求是什么并且需要从你的信息系统中了解什么。因此,使用你的规则引擎语言对本体进行正式的描述。Drools与Java面向对象模型紧密合作,但是它也允许你使用决策表、DSL或你为之提供驱动的其它语言定义更高层次的模型(如Mark关于CLIPS的描述)。<o:p></o:p>
因此,下面是你如何在规则中应用好的模式的一些提示;<o:p></o:p>
- 使用平面模型要比深层嵌套模型更好。通常对于平面模型来说编写规则更容易。<o:p></o:p>
<o:p> </o:p>
- 对规则中将提出的问题先问问自己,是否你可以通过使用业务模型进行回答。如果答案是混乱的,那重构你的模型,再次尝试回答。简单的例子:你的规则将应用在订单,产品以及订单中的产品(让我们称之为项目)上。那么,你的模型是否允许你了解订单?是否容易知道订单中的项目?是否容易了解订单中每个项目的产品明细?如你看到的,这与我们设计数据模型是相似的练习。<o:p></o:p>
<o:p> </o:p>
- 使用自然语言编写你的规则。在你的规则中定义所有对象的引用。对每一个对象定义所有的引用属性。对每一个属性,定义所有该属性可以应用的约束条件。现在检查一下是否你的业务领域模型包含这些对象(fact)以及这些属性,以及是否它可以在这些属性类型上应用这些约束。它看起来好像我们在这里进行面向对象的分析,但它并不是完全一样;我们在更高的概念层次上进行讨论,因为无论你使用什么工具,它需要同样的信息,不管它是基于OO,模板甚至更高级的DSL。<o:p></o:p>
2. 了解你的工具:
显然,了解你所使用的工具以及怎样用工具提供的功能(文本语言,数据表,Web接口或其它什么)来表达知识是有益的。学习工具将花费时间与精力,但它是值得的。你将使用高级特性来编写更好更简单的规则。举一个简单的例子:我经常看到人们使用Eval或函数来编写约束,在Drools中如果能够使用一种更简单的模式约束,那会更加有效率并提高性能。(记住:Eval是魔鬼!)<o:p></o:p>
3. 将所有对象作为fact设置:
<o:p></o:p>
规则引擎通常知道怎样处理fact的相当繁重的装载任务,因此让引擎去发挥它的魔法。如果你想在一个嵌套的对象集合上进行推论,那么将所有的对象都设置到working memory中,不只是顶级的对象,并且确认你的业务模型在它们之间建立了关联。在那之后,编写规则将更加容易,并且引擎能够优化执行效率(对比使用Eval或其它深层次嵌套结构访问)。例如:如果你有一个Order对象包含OrderItem列表,将Order和OrderItem都设置到引擎中(如果你需要在OrderItem上进行推论)。<o:p></o:p>
所有以上的建议都会有例外情况,但是对于常见请况,遵守上面的简易可以帮助你编写更好的规则。<o:p></o:p>
<o:p></o:p>
<o:p> </o:p>