5. Rule
![](https://i-blog.csdnimg.cn/blog_migrate/1c913e6cd9fc9b012b01b8ff17ed4477.png)
Rule 结构是最重要的结构。 Rule 使用了形如“ IF ” something “ THEN ” action (当然,我们的关键字是“ when ”和“ then ”)的形式。
一个规则在一个 package 中必须要有唯一的名字。如果一个名字中含有空格,那就需要将名字放在双引号中(最好总是使用双引号)。
Attribute 是可选的(最好是每行只有一个 Attribute )。
规则的 LHS 跟在“ when ”关键字的后面(最好是另起一行),同样 RHS 要跟在“ then ”关键字后面(最好也另起一行)。规则以关键字“ end ”结束。规则不能嵌套。
5.1 Left Hand Side
Left Hand Side 其实就是规则的条件部分。 LHS 对应的 rail-road 图如下,我们在后面会做进一步解释:
![](https://i-blog.csdnimg.cn/blog_migrate/f06c1bac747ff24eacc72d43eb577a67.png)
5.2 Right Hand Side
Right Hand Side ( RHS )就是规则的结果( consequence )或者动作( action )部分。 RHS 的目的是 retract 或 add facts 到 WorkingMemory 中,还有针对你的 application 的动作。实际上, RHS 是当规则激发( fire )时执行的代码块。在 RHS 中,你可以使用几个方便的 method 来改变 WorkingMemory :
“ modify(obj) ”:告诉引擎一个对象已经发生变化,规则必须重新匹配( obj 对象必须是出现在 LHS 中的对象);
“ assert(new Something()) ”:将一个新的 Something 对象加入 WorkingMemory ;
“ assertLogical(new Something()) ”:与 assert 方法类似。但是,当没有 fact 支持当前激发规则的真实性的时候,这个新对象会自动被 retract ,
“ retract(obj) ”:从 WorkingMemory 中移除一个对象。
这些方法都是宏指令,提供了到 KnowledgeHelper 实例的快捷方式(参考 KnowledgeHelper 接口)。 KnowledgeHelper 接口可以在 RHS 代码块中调用,通过变量“ drools ”。如果你在 assert 进引擎的 JavaBean 中加入“ Property Change Listener ”,在对象发生变化的时候,你就不用调用“ modify ”方法。
5.3 Rule Attributes
![](https://i-blog.csdnimg.cn/blog_migrate/81d4815cbdb735e2940e6e263fe8721c.png)
5.3.1 no-loop
默认值: false
类型: boolean
当在 rule 的 RHS 中修改了一个 fact ,这可能引起这个 rule 再次被 activate ,引起递归。将 no-loop 设为 true ,就可以防止这个 rule 的 Activation 的再次被创建。
5.3.2 salience默认值: 0
类型: int
每个 rule 都可以设置一个 salience 整数值,默认为 0 ,可以设为正整数或负整数。 Salience 是优先级的一种形式。当处于 Activation 队列中时,拥有高 salience 值的 rule 将具有更高的优先级。
5.3.3 agenda-group默认值: MAIN
类型: String
Agenda group 允许用户对 Agenda 进行分组,以提供更多的执行控制。只有具有焦点的组中的 Activation 才会被激发( fire )。
5.3.4 auto-focus默认值: false
类型: boolean
当一个规则被 activate (即 Activation 被创建了),如果这个 rule 的 auto-focus 值为 true 并且这个 rule 的 agenda-group 没有焦点,此时这个 Activation 会被给予焦点,允许这个 Activation 有 fire 的潜在可能。
5.3.5 activation-group默认值: N/A
类型: String
当处于同一个 activation-group 中的第一个 Activation fire 后,这个 activation-group 中其余剩下的 Activation 都不会被 fire 。
5.3.6 duration默认值:没有默认值
类型: long
5.4 Column
![](https://i-blog.csdnimg.cn/blog_migrate/1639dc666de42482b891058770073821.png)
Example 5.1. Column
Cheese( type == " stilton " , price < 10 )
一个 Column 由一个类的一个或多个域约束构成。第一个例子没有约束,它将匹配 WorkingMemory 中所有的 Cheese 实例。第二个例子对于一个 Cheese 对象有两个字面约束( Literal Constraints ),它们被用“,”号隔开,意味着“ and ”。
Example 5.2. Bound Column
这个例子同前一个例子有点类似。但是在这个例子中,我们将一个变量绑定到匹配规则引擎的 Cheese 实例上。这意味着,你可以在另一个条件中使用 cheapStilton ,或者在 rule 的 RHS 中。
5.4.1 Field Constraints
Field Constraints 使规则引擎可以从 WorkingMemory 中挑选出合适的 Fact 对象。一个 Fact 的“ Field ”必须符合 JavaBean 规范,提供了访问 field 的 getter 方法。你可以使用 field 的名字直接访问 field ,或者使用完整的方法名(省略括号)。
例如,以我们的 Chess 类为例,下面是等价的: Cheese(type = = …) 和 Cheese(getType = = …) 。这意味着,你可以使用不太严格遵守 JavaBean 规范对象。尽管如此,你要保证 accessor 方法是不带参数的,以保证它不会改变对象的状态。
注意:如果一个 field 使用原始类型( primitive type ), Drools 将会把它们自动装箱成相应的对象(即使你使用 java 1.4 ),但是在 java 1.4 下却不能自动拆箱。总的来说,尽量在 rule 所使用的类中,使用非原始类型的域。如果是使用 java 5 ,就可以比较随意了,因为编译器会帮你执行自动装拆箱。
5.4.1.1 Operators![](https://i-blog.csdnimg.cn/blog_migrate/5bf66f6c250a90057fe921fc5a560ad5.png)
有效的操作符是同域类型相关的。例如,对于日期域,“ < ”意味着“之前”。“ matches ”只适用于 String 域,“ contains ”和“ excludes ”只适用于 Collection 类型域。
5.4.1.2 字面值约束( Literal Constraints )最简单的域约束就是字面值约束,允许用户将一个 field 约束于一个已知值。
注意:你可以检查域是否为 null ,使用 = = 或 != 操作符和字面值‘ null ’关键字。如, Cheese(type != null) 。字面值约束,特别是“ = = ”操作符,提供了非常快的执行速度,因为可以使用散列法来提高性能。
Numeric
所有标准的 Java 数字基本类型都可以用。
有效操作符:
· ==
· !=
· >
· <
· >=
· <=
Example 5.3 . Numeric Literal ConstraintDate
当前只对“ dd-mm-yyyy ”的日期格式提供默认支持。你可以通过指定 drools.dateformat 系统属性,来改变默认的日期格式。如果需要更多的控制,要用谓词约束( Predicate Constraint )。
有效操作符:
· ==
· !=
· >
· <
· >=
· <=
Example 5.4. Date Literal ConstraintString
可以使用任何有效的 Java String 。
有效操作符:
· ==
· !=
Example 5.5. String Literal ConstraintBoolean
只能用 “ true ”或“ false ”。 0 和 1 不能被识别,而且 Cheese(smelly) 也是不被允许的。
有效操作符:
· ==
· !=
Example 5.6 Boolean Literal ConstraintMatches Operator
Matches 操作符后面可以跟任何有效的 Java 正则表达式。
Example 5.7. Regular Expression ConstraintContains Operator and Excludes Operator
“ contains ”和“ excludes ”可以用来检查一个 Collection 域是否含有一个对象。
Example 5.8. Literal Cosntraints with CollectionsCheeseCounter( cheeses excludes " chedder " )
5.4.1.3 Bound Variable Constraint
可以将 Facts 和它们的 Fields 附给一个 Bound Variable ,然后在后续的 Field Constraints 中使用这些 Bound Variable 。一个 Bound Variable 被称为声明( Declaration )。 Declaration 并不能和“ matches ”操作符合用,但却可以和“ contains ”操作符合用。
Example 5.9. Bound Field using '==' operator
Cheese( type == likes )
在上面的例子中,“ likes ”就是我们的 Bound Variable ,即 Declaration 。它被绑定到了任何正在匹配的 Person 实例的 favouriteCheese 域上,并且用来在下一个 Column 中约束 Cheese 的 type 域。可以使用所有有效的 Java 变量名,包括字符“ $ ”。“ $ ”经常可以帮助你区分 Declaration 和 field 。下面的例子将一个 Declaration 绑定到匹配的实例上,并且使用了“ contains ”操作符。注意: Declaratino 的第一个字符用了“ $ ”:
Example 5.10 Bound Fact using 'contains' operator
Cheesery( cheeses contains $stilton )
5.4.1.4 Predicate Constraints
![](https://i-blog.csdnimg.cn/blog_migrate/fd0e043d0fc4cd7c9442d39708673239.png)
Predicate 表达式可以使用任何有效的 Java 逻辑表达式。先前的 Bound Declaration 可以用在表达式中。
下面的例子将会找出所有男性比女性大 2 岁的 pairs of male/femal people :
Example 5.11. Predicate Constraints
Person( boyAge : age -> ( girlAge.intValue() + 2 == boyAge.intValue() ), sex = = " M " )
5.4.1.5 Return Value Constraints
![](https://i-blog.csdnimg.cn/blog_migrate/fd0e043d0fc4cd7c9442d39708673239.png)
一个 Retrurn Value 表达式可以使用任何有效的 Java 表达式,只要它返回一个对象,不能返回原始数据类型。如果返回值是原始数据类型,要先进行装箱。先前的 Bound Declaration 也可以使用在表达式中。
下面的例子跟上一节的例子一样,也将会找出所有男性比女性大 2 岁的 pairs of male/femal people 。注意:这里我们不用绑定 boyAge ,增加了可读性:
Example 5.12. Return Value Constraints
Person( age = = ( new Integer(girlAge.intValue() + 2 ) ), sex = = " M " )
5.5 Conditional Elements
Conditional Elements 用来连接一个或多个 Columns 。
5.5.1 “ and ”
![](https://i-blog.csdnimg.cn/blog_migrate/32a0caa42677450961cb8666b0757338.png)
Example 5.13. And
Cheese( cheeseType : type ) and Person( favouriteCheese == cheeseType )
5.5.2 “ or ”
![](https://i-blog.csdnimg.cn/blog_migrate/11c42914bf1820cee6bd6af8237d7e6b.png)
Example 5.14. or
Person( sex == " f " , age > 60 ) or Person( sex == " m " , age > 65 )
![](https://i-blog.csdnimg.cn/blog_migrate/1ced854ab624c27681ec9eb2d85ec5dd.png)
Example 5.15. or with binding
pensioner : ( Person( sex == " f " , age > 60 ) or Person( sex == " m " , age > 65 ) )
“ or ” Conditional Element 的使用会导致多条 rule 的产生,称为 sub rules 。上面的例子将在内部产生两条规则。这两条规则会在 WorkingMemory 中各自独立的工作,也就是它们都能进行 match , activate 和 fire 。当对一个“ or ” Conditional Element 使用变量绑定时,要特别小心,错误的使用将产生完全不可预期的结果。
可以将“ OR ” Conditional Element 理解成产生两条规则的快捷方式。因此可以很容易理解,当“ OR ” Conditional Element 两边都为真时,这样的一条规则将可能产生多个 activation 。