5 Drools高级属性
? 这部分,我们来学习一下Drools中的一些高级属性的使用。
5.1 global全局变量
? global关键字可以用来在规则文件中定义全局变量,它可以让应用程序中的对象在规则文件中都能够被访问。可以用来为规则文件提供数据或服务,从而贯穿整个规则文件的执行过程。该关键字的使用方式在下面的例子中会做介绍,我们编写一个规则文件,文件名为globalDemo.drl ,具体代码如下:
package rules;
import com.dream21th.first.utils.CommonUtils;
import java.util.List;
import java.util.ArrayList;
import com.dream21th.first.GlobalDTO;
global java.lang.Integer num; //此处定义一个全局计算数
global CommonUtils utils; //这里定义了一个普通的javaBean
global List<String> list; //这里定义了一个简单的List数组
rule "global_demo_1"
when
GlobalDTO()
then
num++; //计算只在当前规则中有效
System.out.println(utils.whoAmI());
list.add("这是规则global_demo_1");
System.out.println("这是规则global_demo_1的num:"+num);
end
rule "global_demo_2"
when
GlobalDTO()
then
num++; //计算只在当前规则中有效
list.add("这是规则global_demo_2");
System.out.println("这是规则global_demo_2的num:"+num);
end
rule "global_demo_3"
when
GlobalDTO()
then
System.out.println("num:"+num);
System.out.println("list:"+list);
end
? 编写测试案例如下:
@Test
public void testGlobal(){
KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer =kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();
kieSession.setGlobal("utils",new CommonUtils());
Integer num=100;
kieSession.setGlobal("num",num);
List<String> list = new ArrayList();
kieSession.setGlobal("list",list);
kieSession.insert(new GlobalDTO());
kieSession.fireAllRules();
System.out.println("这是外面num:"+num+" 这是外面的list:"+list);
kieSession.dispose();
}
? 其他在本例子使用到的类:
package com.dream21th.first.utils;
public class CommonUtils {
public String whoAmI(){
return "unkonw";
}
}
package com.dream21th.first;
public class GlobalDTO {
}
案例解析:
? 1,本例子中,我们定义了三个global属性的变量,普通的Integer类型的num,自定义的javabean类型的CommonUtils,以及一个简单的List集合类型;
? 2,我们在测试过程中给num的初始值为100,集合list初始为一个空的;
? 3,在规则里面分别对num进行了递增加1,向list中加入了一条数据,这里需要注意对基本类型的修改只限于当前规则,不会外溢到其他规则。
运行测试案例,控制台输出:
unkonw
这是规则global_demo_1的num:101
这是规则global_demo_2的num:101
num:100
list:[这是规则global_demo_1, 这是规则global_demo_2]
这是外面num:100 这是外面的list:[这是规则global_demo_1, 这是规则global_demo_2]
5.2 query查询
? query属性提供了一种查询working memory中符合约束条件的Fact对象的方法。如果我们想知道工作内存中有哪些满足条件的对象,我们就可以通过query关键字属性来实现,具体的使用格式如下:
query 查询的名称(可选参数)
LHS
end
? 接着我们编写如下的查询逻辑:
package rules;
import com.dream21th.first.PersonBasicInfo;
//不带参数的查询
//当前query用于查询Working Memory中age>10的PersonBasicInfo对象
query "query_1"
$personBasicInfo:PersonBasicInfo(age > 10)
end
//带有参数的查询
//当前query用于查询Working Memory中age>10同时name需要和传递的参数name相同的PersonBasicInfo对象
query "query_2"(String nm)
$personBasicInfo:PersonBasicInfo(age > 20 && name == nm)
end
? 编写测试用例代码:
@Test
public void testQuery() {
KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();
PersonBasicInfo personBasicInfo1 = new PersonBasicInfo();
personBasicInfo1.setName("张三");
personBasicInfo1.setMonthIn(BigDecimal.ONE);
personBasicInfo1.setAge(23);
PersonBasicInfo personBasicInfo2 = new PersonBasicInfo();
personBasicInfo2.setName("赵鹏");
personBasicInfo2.setMonthIn(BigDecimal.ONE);
personBasicInfo2.setAge(8);
PersonBasicInfo personBasicInfo3 = new PersonBasicInfo();
personBasicInfo3.setName("李明文");
personBasicInfo3.setMonthIn(BigDecimal.ONE);
personBasicInfo3.setAge(22);
kieSession.insert(personBasicInfo1);
kieSession.insert(personBasicInfo2);
kieSession.insert(personBasicInfo3);
QueryResults results1 = kieSession.getQueryResults("query_1");
int size = results1.size();
System.out.println("size=" + size);
for (QueryResultsRow row : results1) {
PersonBasicInfo personBasicInfo = (PersonBasicInfo) row.get("$personBasicInfo");
System.out.println(personBasicInfo);
}
QueryResults results2 = kieSession.getQueryResults("query_2", "李明文");
size = results2.size();
System.out.println("size=" + size);
for (QueryResultsRow row : results2) {
PersonBasicInfo personBasicInfo = (PersonBasicInfo) row.get("$personBasicInfo");
System.out.println(personBasicInfo);
}
kieSession.dispose();
}
案例说明:
? 1,在这个案例中我们编写了两个查询逻辑,一个方法不带参数,另外一个带有一个参数;
? 2,在测试代码中,我们向工作内存中插入三个对象,并查询,运行结果满足预期。
5.3 function函数
? function关键字用于在规则文件中定义函数,和java类中的方法一样,如果有一部分代码比较长或者多处有使用,我们就可以抽象出函数。使用函数的好处是可以将业务逻辑集中放置在一个地方,根据需要可以对函数进行修改。
? 函数定义的语法结构如下:
function 返回值类型 函数名(可选参数){
//逻辑代码
}
? 我们接下来编写规则functionDemo.drl ,规则文件的具体内容如下:
package rules;
import com.dream21th.first.PersonBasicInfo;
function String doSomething(String something){
return "do "+something;
}
rule "function_1"
when
$p:PersonBasicInfo(name=='functionTest')
then
System.out.println(doSomething("sleep"));
end
? 编写测试案例:
@Test
public void testFunction(){
KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer =kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();
PersonBasicInfo personBasicInfo=new PersonBasicInfo();
personBasicInfo.setName("functionTest");
personBasicInfo.setMonthIn(BigDecimal.ONE);
kieSession.insert(personBasicInfo);
kieSession.fireAllRules();
kieSession.dispose();
}
案例说明:
? 1,编写一个规则,规则中有一个名为doSomething的函数,这个函数没有做很多事情,只是将入参前面加了一个do返回出去;
? 2,规则的触发条件是工作内存中有一个PersonBasicInfo的对象,并且name属性的值为functionTest就会触发,触发后发现调用了写的函数。
5.4 其他一些属性介绍
? 除了上面介绍的一些比较常用的属性外,还有一些属性在实际的开发过程中也会经常使用,下面就来简单介绍一下这些属性及使用方法。
5.4.1 in/not in
? 从名字就可以大概猜到这两个属性的使用场景,这两个属性主要是用来判断一个字符串或者数字在不在一个集合里面。
package rules;
import com.dream21th.first.PersonBasicInfo;
rule "in_demo"
when
$p:PersonBasicInfo(name in ("马超","黄忠","程普"))
then
System.out.println("触发in_demo");
end
rule "not_in_demo"
when
$p:PersonBasicInfo(name not in ("马超","黄忠","程普"))
then
System.out.println("触发not_in_demo");
end
案例说明:第一个规则说的是name属性在"马超",“黄忠”,"程普"三个中才触发;第二个规则说不在这三个属性中才触发。
5.4.2 not
? not用于判断Working Memory中是否存在某个Fact对象,如果不存在则返回true,如果存在则返回false。我们用下面的例子来看一下这个属性的使用
rule "not_1"
when
not PersonBasicInfo()
then
System.out.println("工作内存中没有PersonBasicInfo对象");
end
rule "not_2"
when
not PersonBasicInfo(name=='张飞')
then
System.out.println("工作内存中没有name属性为张飞的PersonBasicInfo对象");
end
5.4.3 条件元素exists
? exists的作用与not相反,用于判断工作内存中是否存在某个Fact对象,如果存在则返回true,不存在则返回false。接下来可能有人会有疑问,我们前面在LHS部分进行条件编写时并没有使用exists也可以达到判断Working Memory中是否存在某个符合条件的Fact元素的目的,那么我们使用exists还有什么意义?其实两者的区别在于:当向Working Memory中加入多个满足条件的Fact对象时,使用了exists的规则只执行一次,不使用exists的规则会执行多次。
? 接下来我们通过下面的例子来看看这个属性的使用:
package rules;
import com.dream21th.first.PersonBasicInfo;
rule "exist_1"
when
exists PersonBasicInfo(name=='潘飞')
then
System.out.println("触发exist_1");
end
rule "no_exist_2"
when
PersonBasicInfo(name=='潘飞')
then
System.out.println("触发exist_2");
end
? 测试案例:
@Test
public void testExists(){
KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer =kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();
PersonBasicInfo personBasicInfo=new PersonBasicInfo();
personBasicInfo.setName("潘飞");
personBasicInfo.setMonthIn(BigDecimal.ONE);
PersonBasicInfo personBasicInfo1=new PersonBasicInfo();
personBasicInfo1.setName("潘飞");
personBasicInfo1.setMonthIn(BigDecimal.ONE);
kieSession.insert(personBasicInfo);
kieSession.insert(personBasicInfo1);
kieSession.fireAllRules();
kieSession.dispose();
}
案例说明:
? 1,向工作内存中插入两个PersonBasicInfo对象,发现带有属性exists的规则只触发一次,不带的执行了2次。
5.4.4 规则继承
? 在编写Drools规则的时候我们可以使用extend来继承另外一个规则,类型java语言中的继承。
rule "rule_1"
when
PersonBasicInfo(age > 10)
then
System.out.println("规则:rule_1触发");
end
rule "rule_2" extends "rule_1" //继承上面的规则
when
/*
**此处的条件虽然只写了一个,但是从上面的规则继承了一个条件,所以当前规则存在两个条件
,即PersonBasicInfo(age < 20)和PersonBasicInfo(age > 10)
*/
PersonBasicInfo(age < 20)
then
System.out.println("规则:rule_2触发");
end
5.4.5 halt
? halt方法的作用是立即终止后面所有规则的执行。
package testhalt
rule "rule_halt_1"
when
then
System.out.println("规则:rule_halt_1触发");
drools.halt();//立即终止后面所有规则执行
end
//当前规则并不会触发,因为上面的规则调用了halt方法导致后面所有规则都不会执行
rule "rule_halt_2"
when
then
System.out.println("规则:rule_halt_2触发");
end
5.4.6 getWorkingMemory
? getWorkingMemory方法的作用是返回工作内存对象。
rule "rule_getWorkingMemory"
when
then
System.out.println(drools.getWorkingMemory());
end
5.4.7 getRule
? getRule方法的作用是返回规则对象(当前规则)。
rule "rule_getRule"
when
then
System.out.println(drools.getRule());
end
//运行结果
[Rule name=rule_getRule, agendaGroup=MAIN, salience=0, no-loop=false]
|