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; 
 
/* 
 * @Author dream21th 
 **/ 
public class CommonUtils { 
 
    public String whoAmI(){ 
        return "unkonw"; 
    } 
} 
 
 
package com.dream21th.first; 
 
/* 
 * 仅作为测试使用 
 * @Author dream21th 
 **/ 
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); 
 
       //将对象插入Working Memory中 
        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.fireAllRules(); 
        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] 

本文参考链接:https://blog.csdn.net/m0_67391870/article/details/123460099
评论关闭
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

Java多线程中Lock锁如何使用