39、Drools语法篇之(when)

模式(pattern )
模式元素是最重要的条件元素。下面的整体关系图表,勾画出了构成模式的约束的各个部分,以及它 们如何一起工作;然后用铁路图表和实例更详细地介绍了每一个。
39、Drools语法篇之(when)_第1张图片
模式整体关系图表
在 ER 图表的顶层,你可以看见该模式由零个或多个约束构成,并且有一个可选择的模式绑定。下面 的铁路图显示了它的语法

Pattern  模式
在它的最简单格式中, 没有约束, 一个模式匹配给定类型的一个事实。 在下面的案例中, 类型为 Cheese, 这意味着模式会 匹配在工作内存中的所有 Cheese 对象
注意类型不必是一些事实对象的实际的类。模式可以引用子类,甚至接口,因此匹配的事实可能来自 不同的类。
为了引用匹配的对象,一个模式可以绑定变量,如$c。前缀符号(`$`)是可选的;在复杂的规则中可能 非常有用,它有助于区别变量和字段。
$c : Cheese()
在模式的扩号内部是所有动作发生的地方。约束可以是一个字段约束,内嵌计算(Inline Eval),或 者一个约束组。约束可以使用:',', '&&' or '||'符号分隔。

字段约束
字段约束为命名字段指定限制;字段名可以有一个可选的变量绑定。 有三种类型的限制:单值限制、复合值限制和多限制。
JavaBeans  作为事实
字段从对象的访问方法派生。如果你的模型对象遵守 Java Bean 模式,那么通过"getXXX" 或"setXXX" 方法暴露字段,这些方法都是无参返回东西。在模式内部,可以使用 bean 命名协议访问字段,所以, "getType"将作为"type"被访问。Drools 使用标准的自省(Introspector)类做这种是映射。 例如, 有关我们的 Cheese 类,模式 Cheese(type == "brie")应用了一个 Cheese 实例的 getType()方法。 如果一个字段名没有发现, 编译器将采用一个无参数的方法作为名字。 因此,由于约束 Cheese(toString == "cheddar"), 调用了 toString()方法。 在这种情况下, 你使用正确的大小写方法全名, 但是仍无括号。 请确保你访问的方法没有使用参数,并且在事实访问器(accessors)中,它没有改变在某种程序上可 能影响到规则的对象状态。记住规则引擎有效地缓存了匹配的结果,使它在调用之间更快。

限定标识符
也可以使用枚举,支持 jdk1.4 和 5 样式的枚举。对于后者,你必须使用一个 JDK 5 环境中执行。
布尔型字面文字限制
Cheese( smelly == SomeClass.TRUE )
绑定变量限制
变量可以绑定到事实或它们的字段,然后在推论字段约束中使用。一个绑定变量被称为一个声明。有 效的运算符由被约束字段的类型确定;可以的地方会尝试强制。绑定变量限制使用'=='提供更快的执 行,象我们可以使用散列(hash)索引提高性能一样。
Person( likes : favouriteCheese )
Cheese( type == likes )
这里,likes 是绑定到它声明的任何 Person 实例的 favouriteCheese 字段的变量。它被用于约束随后模 式中的 Cheese 的类型。可以使用任何有效的 Java 变量名,它可以使用一个前缀'$',你常看见用它来 区分字段声明。下面的例子,显示了一个$stilton 声明,绑定到第一个匹配的、并且使用了 contains 运算符的模式的对象——注意,可选'$'的使用。
复合值限制
复合值限制被用于超过一个可能的值匹配的地方。目前只支持  in 和 no in 运算符这个运算符的第二 个操作数必须是一个逗号分开的值列表,用括号括起来的。值可以是用变量、字面文字、返回值或限 定标识符提供的。这两个运算符实际是“语法糖(syntactic sugar)”,内部使用'!=' 和'=='运算符改写 为多限制的一个列表。
39、Drools语法篇之(when)_第2张图片
使用 in 的复合值限制
Person( $cheese : favouriteCheese )
Cheese( type in ( "stilton", "cheddar", $cheese )
多限制
简单的多限制使用 & &
Person( age > 30 && < 40 )
复杂多约束使用分组多限制
Person( age ( (> 30 && < 40) ||  (> 20 && < 25) ) )

这里 and  or  就不多解释了。 我们说一说 比较重要的一些when 条件约束元素

条件元素 eval

条件元素 eval 本实上是包罗万象的,它允许执行任何语义代码(返回一个 boolean 原型)。这个代码 可以引用绑定在规则 LHS 中的变量,以及在规则包中的函数。滥用 eval,减少了你的规则的声明, 可能导致引擎的性能较差。虽然 eval 可以用在模式中的任何地方,但是最佳作法是把它作为规则的 LHS中的最后的条件元素添加。
Evals 没有被索引,因此不如字段约束有效果。 然而,当函数返回随着时间推移而不允许在字段约束中使用的变化值时,使用 evals 比较理想。

条件元素 not

条件元素 not 是一阶逻辑的不存在(non-existential)量词,用于检查在工作内存中不存在某东西。把 "not"看作“一定没有……”的意思。
关键字 not 紧跟着用扩号扩起它所应用的条件元素。在单模式的最简情况下(如下所示),你可以选
择忽略扩号
not Bus()
条件元素     exists 

条件元素 exists 是一阶逻辑的存在(existential)量词,用于检查在工作内存中存在某东西。把"exists" 看作“至少有一个……”的意思。
关键字 exits 紧跟着用扩号扩起它所应用的条件元素。在单模式的最简情况下(如下所示),你可以 选择忽略扩号。
exists Bus()
exists Bus(color == "red")
//  括号是可选的:
exists ( Bus(color == "red", number == 42) )
//  exists ”与嵌套插入   括号是必需的:
exists ( Bus(color == "red") and  Bus(color == "blue") )
我们对上面的例子做一个简单的说明 
 exists ( Bus(color == "red", number == 42) )  很简单,就是说Bus的color属性为red  number属性为42当这两个条件都满足是,返回值为true
exists ( Bus(color == "red") and Bus(color == "blue") ) 这个是指  color 匹配多个值时,当然 也要插入两个对象,这两个对象里 一个存放 red  一个存入 blue。  exitsts会去工作内在中查找对应对象的内的属性值,进行对比。
Person p=new Person("张三",10);
Person ps=new Person("李四",50);
条件元素 forall

在Dools中的条件元素forall完全支持一阶逻辑。 当匹配第一个模式的所有事实匹配所有剩余模式时,条件元素 forall 求值为 true。例如:
rule "All English buses are red"
    when
        forall( $bus : Bus( type == 'english')
        Bus( this == $bus, color = 'red' ) )
    then
        # all english buses are red
end
在上面的规则中, 我们 “选择” 类型为"english"的所有 Bus 对象。 然后, 对每个匹配这个模式的事实, 我们计算其随后的模式,如果为匹配,forall 条件元素求值为 ture。
要声明在工作内存中给定类型的所有事实必须匹配一组约束, 可以用单个模式简明编写 forall。 例如:
rule "All Buses are Red"
    when
        forall( Bus( color == 'red' ) )
    then
        # all asserted Bus facts are red
end
另外一个例子,显示了 forall 内部的多个模式:
rule "all employees have health and dental care programs"
    when
        forall( $emp : Employee()
                    HealthCare( employee == $emp )
                    DentalCare( employee == $emp )
                    )
    then
        # all employees have health and dental care
end
为了完善的表现, forall 可以被嵌套在其他条件元素同部。 例如, forall 可以被用在 not 条件元素内部。
注意,单个模式时扩号是可选的,所以,使用嵌套 forall,必须使用扩号:
forall 与 not 条件元素的组合
rule "not all employees have health and dental care"
    when
        not ( forall( $emp : Employee()
                HealthCare( employee == $emp )
                DentalCare( employee == $emp ) )
            )
    then
        # not all employees have health and dental care
end
另外注意,not( forall( p1 p2 p3...))等价于:
not(p1 and not(and p2 p3...))
注意 forall 是一个域分隔符也很重要。因此,它可以使用任何前面绑定的变量, 但是在它里面绑定的变量不能在它的外面使用
条件元素 from

条件元素 from 让用户指定任意的资源,用于 LHS 模式的数据匹配。这允许引擎在 非工作内存数据基础上进行推断。数据源可以是一个绑定变量的一个子字段或者方法调用的结果。它是一个超强结 构,允许开箱即可与其他应用程序组件或框架集成使用。常见的集成例子是使用 hibernate 命名查询 随时从数据库索取数据 用于定义数据源的表达式是任何遵守标准MVEL语法的表达式。 它允许你轻松地使用对象属性导航, 执行方法调用,以及访问映射和集合的元素
下面是一个推断的例子,绑定了另一个模式的子字段:
rule "validate zipcode"
    when
        Person( $personAddress : address )
        Address( zipcode == "23920W") from $personAddress
    then
        # zip code is ok
end

利用 Drools 新表现的所有灵活性,你可以用多种方式解决这个问题。下面是相同的,除显示你如何 与'from'一起使用一个图形符号之外。
rule "validate zipcode"
    when
        $p : Person( )
        $a : Address( zipcode == "23920W") from $p.address
    then
        # zip code is ok
end
前面的例子使用单个模式进行计算。 条件元素 from 也支持对象源,其返回一个对象集合
在这种情 况下,from 将会迭代集合中的所有对象,并分别尝试匹配它们每一个。例如,如果我们希望一条规 则,在一个定单中的每个项目实施 10%的折扣,我们可以做:
rule "apply 10% discount to all items over US$ 100,00 in an order"
    when
        $order : Order()
        $item : OrderItem( value > 100 ) from $order.items
    then
        # apply discount to $item
end
在上面的例子中,对每个给定的定单,每个项目的值大于 100 时,将使规则引发一次。
然而,在使用 form 时,你必须小心,特别是与 lock-on-active 规则属性联合使用时,因为它可能产生 不希望的结果。
考虑前面提供的例子,现在可略加修改如下:
rule "Assign people in North Carolina (NC) to sales region 1"
    ruleflow-group "test"
    lock-on-active true
    when
        $p : Person( )
        $a : Address( state == "NC") from $p.address
    then
        modify ($p) {} #Assign person to sales region 1 in a modify block
end
rule "Apply a discount to people in the city of Raleigh"
    ruleflow-group "test"
    lock-on-active true
    when
        $p : Person( )
        $a : Address( city == "Raleigh") from $p.address
    then
        modify ($p) {} #Apply discount to person in a modify block
end
在上面的例子中,销售 1 区为北卡罗莱纳州(NC),在罗利(Raleigh)城中的人,给予优惠;即  你希望两条规则都被激活且被引发。相反,你会发现只有第二条规则被引发了
如果你打开了审计日志,你将会看见,在第二条规则引发时,它禁用了第一条规则。因为当一组事实 变化时,lock-on-active 规则属性防止规则创建新的活动,所以第一条规则未能被重新激活。虽然该组 事实没有被改变,而实际上每次计算使用的 from 都会产生一个新的事实
首先,  检查你为什么使用上面的模式是重要的。  你可能有多条规则横跨不同的规则流 (rule-flow) 组。 当你修改工作内存时, 在你的规则流下游的其他规则 (在不同规则流组中的) 需要被重新计算, modify 的使用至关重要然而,你不希望在相同规则流组中的其他规则在一个另外的递归中被设置为活动 在这种情况下,no-loop 属性是无效的,因为它只防止规则的自身递归激活。因此,你求助于 lock-on-active
有几种方法解决这个问题:
1、 当你可以断言所有事实到工作内存中,或者在你的约束表达式中使用嵌套对象引用时(下面 所示),应避免使用 from
2、 把用于修改块中的变量的赋值语句作为你的条件(LHS)中的最后一条放置
3、 当你可以显式地管理在同一规则流组内的规则在另外一个中如何设置活动时, 应避免使用 lock-on-active

当你可以直接断言所有事实到工作内存时, 首选解决方案是尽量减少 from 的使用。 在上面的例子中, Person 和 Address 实例都可以被断言到工作内存中。在这种情况下,因为该图相当简单,更容易的解 决方案是如下这样修改你的规则
rule "Assign people in North Carolina (NC) to sales region 1"
    ruleflow-group "test"
    lock-on-active true
    when
        $p : Person(address.state == "NC" )
    then
        modify ($p) {} #Assign person to sales region 1 in a modify block
end
rule "Apply a discount to people in the city of Raleigh"
    ruleflow-group "test"
    lock-on-active true
    when
        $p : Person(address.city == "Raleigh" )
    then
        modify ($p) {} #Apply discount to person in a modify block
end
现在,你会发现两条规则如希望的一样被引发。然而,它并不总是可以访问上述的嵌套事实。考虑一 个例子,Person 持有一个或多个 Address,并且你希望使用一个存在的量词匹配至少有一个符合一定 条件的地址的人。在这种情况下,你将不得不求助于 from 的使用,在集合上进行推断。 有几种 from 的用法完成这种情况, 并且不是所有它们与 lock-on-active 一起使用会表现出问题。 
例如, 下面的 from 用法,使两条规则如希望的一样被引发
rule "Assign people in North Carolina (NC) to sales region 1"
    ruleflow-group "test"
    lock-on-active true
    when
        $p : Person($addresses : addresses)
        exists (Address(state == "NC") from $addresses)
    then
        modify ($p) {} #Assign person to sales region 1 in a modify block
end
rule "Apply a discount to people in the city of Raleigh"
    ruleflow-group "test"
    lock-on-active true
    when
        $p : Person($addresses : addresses)
        exists (Address(city == "Raleigh") from $addresses)
    then
        modify ($p) {} #Apply discount to person in a modify block
end

条件元素 collect

39、Drools语法篇之(when)_第3张图片

条件元素 collect 允许规则在来自特定资源或工作内存的一个对象集合上进行推断。在一阶逻辑术语 中,这是一个基数量词。一个简单的例子:
import java.util.ArrayList
rule "Raise priority if system has more than 3 pending alarms"
when
    $system : System()
        $alarms : ArrayList( size >= 3 )
        from collect( Alarm( system == $system, status == 'pending' ) )
    then
        # Raise priority, because system $system has
        # 3 or more alarms pending. The pending alarms
        # are $alarms.
end
在上面的例子中,该规则将为每个特定系统在工作内存中为查找所有紧急报警,并在 ArrayLists 中聚 合它们。如果为一个特定系统找到了 3 个或更多,该规则被引发。
collect 的结果模式可以是任何具体的类,  其实现了 java.util.Collection 接口, 并且提供了一个无参公共 构建函数。这意味着,你可以使用 Java 集合,如 ArrayList, LinkedList,HashSet,等等, 或者你自 己的类,只要实现了 java.util.Collection 接口,并且提供了一个无参公共构建函数。 资源和结果模式都可以象任何其他模式一样被约束。
在 collect 条件元素之前的变量绑定是在资源和结果模式两个作用域中,因此你可以使用它们约束你 的资源和结果模式。但是注意,collect 是一个域绑定分隔符,所以任何在它内部的绑定不可用于它的 外部。
collect 认可嵌套的 from 条件元素。下面的例子是一个有效的 collect 用法:

import java.util.LinkedList;
    rule "Send a message to all mothers"
        when
            $town : Town( name == 'Paris' )
            $mothers : LinkedList()
            from collect( Person( gender == 'F', children > 0 ) from $town.getPeople() )         
        then
        # send a message to all mothers
    end

条件元素 accumulate
39、Drools语法篇之(when)_第4张图片
条件元素 accumulate 是一个更灵活强大的 collect 形式,在这个意义上,它可以被用来做 collect 所做 的事,也可以实现 collect 不能做的事。它主要做的事是允许规则迭代整个一个对象的集合,为每个 元素定制执行动作,并在结束时返回一个结果对象。
 accumulate  既支持预定义的累积函数的使用,或也可以使用内联的自定义代码,内联定制代码应该避免,因为它是规则的作者更难维护,并且经常导致代码重复 

Accumulate 功能更容易测试和重用


Accumulate 还支持多个不同的语法。首选的语法是顶级积累,如上所述波纹管,但所有其他语法支持向后兼容。


Accumulate CE (preferred syntax)
顶级accumulate 语法是最紧凑和灵活的语法。简化的语法如下:
accumulate( ;  [;] )
例如,一个规则来计算最小,最大,使用

Accumulate 

rule "取对象中的最大值,和最小值"
dialect "mvel"
when

       accumulate(Person($value:age),
                    $min:min($value),
                    $max:max($value);
                      $max<=5
)
then
System.out.println($min+">>>>>>>>>>>"+$max);
end
Drools附带几个内置的accumulate功能,包括:

average   平均值

min          最小值

max         最大值

count       统计

sum         求和

collectList   返回List  

collectSet  返回HastSet


所有的传入的值的Person属性age都减1
rule "sun求和后减1"
dialect "mvel"
 when
//$n:Number() from
  accumulate(Person($value:age),
   $sum:sum($value-1)
         )
 then
   System.out.println("求和减1>>>>>>>>>>>>"+$sum);
end

Accumulate 函数都是可以插拔的,这意味着,如果需要,定制,领域特定的功能可以很容易地添加到规则引擎,可以开始使用它们没有任何限制。实现一个新的 Accumulate函数所有需要做的是创建一个Java类,该类实现
AccumulateFunction

接口,在6.4版本中j与官方上说明的不一样。如何新建,去官网上有说明。我这里就不多说什么了。
那新建的这个自定义的函数(方法) 我们应该怎么用呢。其实很简单。 引用就可以用了,只是在引用时,加一个关键字就OK
import  accumulate  com.drools.TestAccunmulateneeded getResult
getResult 在自定义的类中可以写多个。 也都能正常使用,这就说明,可以在同一个类可以写多个函数,即也可以对原来的方法 进行修改。  
内置的函数(总和、平均值等)是由引擎自动导入。只有用户定义定制的累积函数需要显式导入。

Accumulate with inline custom code
这个语法在刚研究的时候,官方就给你出了一个说明:
使用 inline  定制code的accumulate 不是一个好的做法,原因有以下几点:维护和测试困难规则,使用它们代码重用性不高,好比在JSP中写java是一个道理,实现自己的accumulate时能非常简单明了,易于单元测试和使用,这些是重要的,这种形式的accumulate只支持身后兼容
下面是inline 的语法结构
from accumulate(,init(),action(),reverse(),result() )
下面我们对这些语法进行一个说明:
:这个表示源模式。用法:也就是我们常用手 Object(xx:XX属性)  这个会去匹配每一个源对象。
:用法说明:init 是做初始化用的,简单的说,在source pattern 遍历完之后 就已经触发,有点像for的开头
: 用法说明:action 会执行所以满足条件的源对象进行操作,像是for的方法体。在里面可写java code
这是一个可选的被选方言的语义代码块,如果存在,将为不再匹配资源 模式的每个资源对象执行。这个代码块的目的是不做在 块中做的任何计算,所 以,当一个资源对象被修改或删除收时,引擎可能做递减计算,极大地提升了这些操作的性
:  返回值,是根据action上面两个遍历出来的结果进行一个返回,这个返回值中也可以进行计算。
: 返回值类型,在返回值的类型再一次进行匹配,如果匹配不成功则返回false。
举一下例子先来说明一下 注: 没使用
rule "测试accumulatefrom用法1"
dialect "mvel"
when

$total : String() from
       accumulate(Person($value:dous),
                  init( Double total = 0.1; Person p = new Person();),
                  action( total += $value; ),
                  result( p )
         )
then
System.out.println($total+"accumulate from 用法 求和");
end
在上面的例子中,我们可以清楚的看到,init 是做了一些初始化的工作,action做的是迭代并计算的操作,result 是返回结果,这个规则可以返回类型 是在from前面定义的类型,上述例子中返回值是p 它是一个Person的类,因为Person有toString(),所以可正常返回,还能返回更多的类型与计算,这个得自己摸索研究了。
使用Java作为语义方言的例子,因此,注意使用分号作为初始化语句分隔符是强制性的,行动和反向代码块。 结果是一个表达式,因此,它不承认';'。 如果用户使用其他方言,他必须服从,方言的具体语法。
和之前所述的,reverse code 是可选的,但是强烈建议用户官写,为了受益于改进的性能update and delete
下面我们就谈一谈 例子中没有的 reverse 属性吧
首先我们先看一下java代码的用法:不多解释,很简单的调用。
@Test
public void  测试accumulatefrom用法reverse() throws Exception {
Resource dis = ResourceFactory.newClassPathResource("rules/testdrl/accumulatefreverse.drl", TestTemplate01.class);
KieHelper helper = new KieHelper();
helper.addResource(dis, ResourceType.DRL);
KieSession ksession = helper.build().newKieSession();
    for(int i=1;i<6;i++){
    Person person=new Person();
    person.setDous(1.0+i);
    person.setAge(i);
    ksession.insert(person);
}
 int i = ksession.fireAllRules(new RuleNameStartsWithAgendaFilter("测试accumulatef"));   
System.out.println( "     " + i + "次");
ksession.dispose();
}
DRL文件的使用:

/*rule "测试accumulatefrom3用法reverse2"
dialect "mvel"
when
    $ps:Person(dous>=3)
then
    $ps.setDous(1.2);
    update($ps);
   System.out.println($ps.dous);
end*/
//为什么会将上面这一规则注释,因为根据调用方法,此规则会先执行,会影响到后面的规则

rule "测试accumulatefrom用法reverse"
dialect "mvel"
when
$total : Double() from
       accumulate(Person(dous>=3,$age:age),
                  init(Double totls = 0.0),
                  action(totls+=$age;System.out.println(totls+">>>>>>>>>");),
                  reverse( totls-=$age;   System.out.println(totls+"<<<<<<<<");),//,
result( totls )
         )

then
System.out.println($total+"+++++++++++");//+$s.count+$s.name);
end

rule "测试accumulatefrom3用法reverse"
dialect "mvel"
when
$ps:Person(dous>=3)
then
$ps.setDous(1.2);
    update($ps);
   System.out.println($ps.dous);
end

简单的说明一下上面的例子:规则先会执行from用法reverse的这个规则,因为有满足的条件,所以会执行,但执行完成后 执行from3用法reverse 这个规则,这个规则用了update 方法,将值改了,所以会重新
下面就针对上面的例子我们做一个总结:
1、accumulate的使用,有一个很重要的函数 action。这个函数提供了匹配源模式的执行动作
2、将action看成两个状态,当源对象匹配源模式时,定会触发action,我将触发过action的源对象称为有状态的(等同于标记),反之为无状态的
3、当我们传入的源对象在RHS中或者是其他规则的RHS中发生了改变(update,insert...),则会触发所有满足条件规则的再次执行。
4、当规则再次被执行时,遇到accumulate时,则有状态的源对象会先执行reverse函数进行"回滚"操作,并将修改后的源对象再次与accumulate条件进行比较,如果比较为true 则该对象(被修改过的)会再次触发action函数,如果比较为false则不会执行action函数
5、当规则再次被执行时,遇到accumulate时,则无状态的源对象会与accumulate条件进行比较,如果比较为true 则该对象(被修改过的)会第一次触发action函数,如果比较为false则不会执行action函数。

注:在我的的多方面测试
accumulate
中,得出几个结论:
1、accumulate有三种形式,分别是 inline 、$min:min(XXX),min();
2、inline 这种形式虽然官方不推荐,不过不代表不能使用,这种形式
3、$min:min(XXX)这只是其中的一种写法,但要注意的是,如果在函数前面加了$xxx变量时,则accumulate不是使用from 方式,至于如何取$XXX变量的值,和模式方式是一样。当然 根据上面的介绍.我们也可以通过在函数的结束符";"后面加条件约束.引用的方法也是同模式方式一样。

rule "取对象中的最大值,和最小值"
dialect "mvel"
when

       accumulate(Person($value:age),
$min:min($value),
$max:max($value);
                  $max<=5
)
then
System.out.println($min+">>>>>>>>>>>"+$max);
end
4、min()写法,前面没有加任何的变量引用说明,当然也不可能在函数的结束符";"后面再加条件约束,并且,想要使用函数中返回的结果,在这种没有引用变量的前提下,则必须要引用from 关键字, 但from关键字有一个问题,就是返回的结果,必须是一个(表示说源模式结束符后面只能有一个函数),且使用函数时,不能有变量引用,这样才能正常使用from。
rule "min的使用"
dialect "mvel"
when
$n:Number()
accumulate(Person($value:age);
                 min($value)
         )
then
System.out.println("min的使用");
end
5、根据上面的说法 使用 accumulate 语法上如果source pattern  结束符后面函数的结果有变量,则不能使用from,且使用from 返回结果必须是一个。
上面说的其实都是accumulate中自带的一些函数和语法,那是远远不够的,accumulate的强大远远在我上面的例子之上,下面我们就再深入一点:试一下自定义函数的用法(是不是很吊的样子......)
首先,我们要实现一个接口,在6.4版本中要AccumulateFunction
注:(官方上给出的接口在6.4版本中是不能用的)
实现了接口会重写里面的方法:
package com.drools;

import org.kie.api.runtime.rule.AccumulateFunction;

import java.io.*;

/**
 * Created by kangz on 2016/9/6.
 */
public class TestAccunmulateneeded implements AccumulateFunction{



public static class Factorial implements Externalizable {
public Factorial(){}

public double total = 1;
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeDouble(total);
}

@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
total=in.readDouble();
}
    }


@Override
public Class getResultType() {
return Number.class;

}

@Override
public Serializable createContext() {
return new Factorial();
}

@Override
public void init(Serializable serializable) throws Exception {
Factorial factorial= (Factorial) serializable;
factorial.total=1;
}

@Override
public void accumulate(Serializable serializable, Object o) {
Factorial factorial= (Factorial) serializable;
factorial.total *= ((Number)o).doubleValue();
}

@Override
public void reverse(Serializable serializable, Object o) throws Exception {
    }

@Override
public Object getResult(Serializable serializable) throws Exception {
Factorial factorial= (Factorial) serializable;
Double d  =new Double(((Factorial) serializable).total ==1?1:((Factorial) serializable).total);
        return d;
}

@Override
public boolean supportsReverse() {
return true;
}

@Override
public void writeExternal(ObjectOutput out) throws IOException {

    }

@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {

    }
}
上面则就是自定义函数的例子。
如果想知道什么时候调用这些方法,则可以通过在方法中打印输出,后续我会将这些方法的用法及作用做一个详细的说明,现在先卖个关子。
那我们写好上自定义函数了,我们在怎么用才行呢。这个简单,想想之前的function 外部方法的使用,想到这里,你就应该明白了,不过关键字不同。
import  accumulate  com.drools.TestAccunmulateneeded 自定义的名称 
通过方面的方法,我们就能使用我们自定义的函数了,但要注意的是,使用 accumulate时,返回值上面有说过,这里不多说了。用法和sum,min等等 是一样的,但要注意的是,如果我们自定的名称是sum ,min等等,调用用的也是自带的方法,不会对原方法进行重写,那具体的用法是这样的:
import  accumulate  com.drools.TestAccunmulateneeded factorial
rule "自定义函数阶乘"
dialect "mvel"
when
//$n:Number() from
accumulate(Person($value:age !=null ) ,
$factorial:factorial($value)
         )
then
System.out.println("自定义函数>>>>>>>>>>>>"+$factorial);
end

下面是小编的微信转帐二维码,小编再次谢谢读者的支持,小编会更努力的

----请看下方↓↓↓↓↓↓↓

百度搜索 Drools从入门到精通:可下载开源全套Drools教程

深度Drools教程不段更新中:


更多Drools实战陆续发布中………

扫描下方二维码关注公众号 ↓↓↓↓↓↓↓↓↓↓



你可能感兴趣的:(drools规则引擎,应用,扩展,函数,drools)