Drools高级语法(6/6)

目录

1、global全局变量

2、query查询

3、function函数

4、LHS加强

4.1、复合值限制in/not in

4.2、条件元素eval

4.3、条件元素not

4.4、条件元素exists

4.5、规则继承

5、RHS加强

5.1、halt

2、getWorkingMemory

3、getRule

6、规则文件编码规范


1、global全局变量

global关键字用于在规则文件中定义全局变量,它可以让应用程序的对象在规则文件中能够被访问。可以用来为规则文件提供数据或服务。

语法结构为:global 对象类型 对象名称

在使用global定义的全局变量时有两点需要注意:

1、如果对象类型为包装类型时,在一个规则中改变了global的值,那么只针对当前规则有效,对其他规则中的global不会有影响。可以理解为它是当前规则代码中的global副本,规则内部修改不会影响全局的使用。

第一步:编写global.drl

package testglobal
/*
    此规则文件用于测试global全局变量
*/
global java.lang.Integer count //定义一个包装类型的全局变量

rule "rule_global_1"
    when
    then
        count += 10;//对于包装类型的全局变量的修改只针对当前规则生效
        System.out.println("规则:rule_global_1触发了、、、");
        System.out.println("全局变量count计算之后的值为: " + count);
end

rule "rule_global_2"
    when
    then
        System.out.println("规则:rule_global_2触发了、、、");
        System.out.println("全局变量count计算之后的值为: " + count);
end

第二步:编写测试类

        @Test
        public void test5() throws InterruptedException
        {
            //设置日期格式
            System.setProperty("drools.dateformat","yyyy-MM-dd HH:mm");
            KieServices kieServices = KieServices.Factory.get();
            KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
            final KieSession session = kieClasspathContainer.newKieSession();

            //设置全局变量,名称和类型必须和规则文件中定义的全局变量名称对应
            session.setGlobal("count", 5);

            //激活
            session.fireAllRules();

            //关闭会话
            session.dispose();

        }

测试结果

Drools高级语法(6/6)_第1张图片

2、如果对象类型为集合类型或JavaBean时,在一个规则中改变了global的值,对java代码和所有规则都有效。

集合类型:

package testglobal
/*
    此规则文件用于测试global全局变量
*/
global java.lang.Integer count //定义一个包装类型的全局变量
global java.util.List gList  //定义一个集合类型的全局变量
rule "rule_global_1"
    when
    then
        count += 10;//对于包装类型的全局变量的修改只针对当前规则生效
        System.out.println("规则:rule_global_1触发了、、、");
        System.out.println("全局变量count计算之后的值为: " + count);

        gList.add("itcast");  //修改集合类型的全局变量
        System.out.println("全局变量gList的size:" + gList.size());
end

rule "rule_global_2"
    when
    then
        System.out.println("规则:rule_global_2触发了、、、");
        System.out.println("全局变量count计算之后的值为: " + count);
        System.out.println("全局变量gList的size:" + gList.size());
end
        @Test
        public void test5() throws InterruptedException
        {
            //设置日期格式
            System.setProperty("drools.dateformat","yyyy-MM-dd HH:mm");
            KieServices kieServices = KieServices.Factory.get();
            KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
            final KieSession session = kieClasspathContainer.newKieSession();

            //设置全局变量,名称和类型必须和规则文件中定义的全局变量名称对应
            session.setGlobal("count", 5);

            List list = new ArrayList();
            list.add("itheima");
            session.setGlobal("gList", list);

            //激活
            session.fireAllRules();

            System.out.println("在Java程序中全局变量glist的size为:" + list.size());

            //关闭会话
            session.dispose();

        }

Drools高级语法(6/6)_第2张图片

自定义对象类型

package testglobal
import com.itheima.drools.service.UserService
/*
    此规则文件用于测试global全局变量
*/
global java.lang.Integer count //定义一个包装类型的全局变量
global java.util.List gList  //定义一个集合类型的全局变量
global UserService userService //定义一个JavaBean类型的全局变量

rule "rule_global_1"
    when
    then
        count += 10;//对于包装类型的全局变量的修改只针对当前规则生效
        System.out.println("规则:rule_global_1触发了、、、");
        System.out.println("全局变量count计算之后的值为: " + count);

        gList.add("itcast");  //修改集合类型的全局变量
        System.out.println("全局变量gList的size:" + gList.size());
        userService.save();
end

rule "rule_global_2"
    when
    then
        System.out.println("规则:rule_global_2触发了、、、");
        System.out.println("全局变量count计算之后的值为: " + count);
        System.out.println("全局变量gList的size:" + gList.size());
        userService.save();
end
        @Test
        public void test5() throws InterruptedException
        {
            //设置日期格式
            System.setProperty("drools.dateformat","yyyy-MM-dd HH:mm");
            KieServices kieServices = KieServices.Factory.get();
            KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
            final KieSession session = kieClasspathContainer.newKieSession();

            //设置全局变量,名称和类型必须和规则文件中定义的全局变量名称对应
            session.setGlobal("count", 5);

            List list = new ArrayList();
            list.add("itheima");
            session.setGlobal("gList", list);

            session.setGlobal("userService", new UserService());

            //激活
            session.fireAllRules(new RuleNameStartsWithAgendaFilter("rule_global"));

            System.out.println("在Java程序中全局变量glist的size为:" + list.size());

            //关闭会话
            session.dispose();

        }

Drools高级语法(6/6)_第3张图片

2、query查询

query查询提供了一种查询working memory中符合约束条件的Fact对象的简单方法。它仅包含规则文件中的LHS部分,不用指定“when”和“then”部分并且以end结束。具体语法结构如下:

query 查询的名称(可选参数)
    LHS
end

具体操作步骤:

第一步:编写规则文件/resources/rules/query.drl

package testquery
import com.itheima.drools.entity.Student
/*
    此规则文件用于测试query查询
*/

//不带参数的查询
//当前query用于查询Working Memory中age>10的Student对象
query "query_1"
    $student:Student(age > 10)
end

query "query_2"(String sname)
    $student:Student(age > 5 && name == sname)
end

第二步:编写单元测试

@Test
        public void test6()
        {
            //设置日期格式
            System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm");
            KieServices kieServices = KieServices.Factory.get();
            KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
            final KieSession session = kieClasspathContainer.newKieSession();
            
            Student student1 = new Student();
            student1.setAge(50);
            student1.setName("张三");
            session.insert(student1);

            Student student2 = new Student();
            student2.setAge(50);
            student2.setName("李四");
            session.insert(student2);

            //根据名称调用规则文件中定义的查询
            QueryResults result1 = session.getQueryResults("query_1");
            int size = result1.size();
            System.out.println("符合条件的Fact对象个数" + size);
            for (QueryResultsRow row : result1)
            {
                Student s = (Student)row.get("$student");
                System.out.println(s);
            }

            QueryResults result2 = session.getQueryResults("query_2", "张三");
            int size2 = result2.size();
            System.out.println("符合条件的Fact对象个数" + size2);
            for (QueryResultsRow row : result2)
            {

                Student s = (Student)row.get("$student");
                System.out.println(s);
            }
//            session.fireAllRules();

            //关闭会话
            session.dispose();
        }

Drools高级语法(6/6)_第4张图片

3、function函数

 

function关键字用于在规则文件中定义函数,就相当于java类中的方法一样。可以在规则体中调用定义的函数。使用函数的好处是可以将业务逻辑集中放置在一个地方,根据需要可以对函数进行修改。

函数定义的语法结构如下:

function 返回值类型 函数名(可选参数){
    //逻辑代码
}

具体操作步骤:

第一步:编写规则文件/resources/rules/function.drl

package testfunction
import com.itheima.drools.entity.Student
/*
    此规则文件用于测试function函数
*/
 
//定义一个函数
function String sayHello(String name)
{
    return "hello " + name;
}

rule "rule_function_1"
    when
        $student:Student(name != null)
    then
        //调用上面定义的函数
        String ret = sayHello($student.getName());
        System.out.println(ret);
end

第二步:编写单元测试

KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();
​
Student student = new Student();
student.setName("小明");
student.setAge(61);
​
kieSession.insert(student);
​
kieSession.fireAllRules();
kieSession.dispose();

4、LHS加强

在规则体中的LHS部分是介于when和then之间的部分,主要用于模式匹配,只有匹配结果为true时,才会触发RHS部分的执行。

4.1、复合值限制in/not in

复合值限制是指超过一种匹配值的限制条件,类似于SQL语句中的in关键字。Drools规则体中的LHS部分可以使用in或者not in进行复合值的匹配。具体语法结构如下:

Object(field in (比较值1,比较值2...))

举例:

$s:Student(name in ("张三","李四","王五"))
$s:Student(name not in ("张三","李四","王五"))

4.2、条件元素eval

eval用于规则体的LHS部分,并返回一个Boolean类型的值。语法结构如下:

eval(表达式)

举例:

eval(true)
eval(false)
eval(1 == 1)

4.3、条件元素not

not用于判断Working Memory中是否存在某个Fact对象,如果不存在则返回true,如果存在则返回false。语法结构如下:

not Object(可选属性约束)

举例:

not Student()
not Student(age < 10)

4.4、条件元素exists

exists的作用与not相反,用于判断Working Memory中是否存在某个Fact对象,如果存在则返回true,不存在则返回false。语法结构如下:

exists Object(可选属性约束)

举例:

exists Student()
exists Student(age < 10 && name != null)

在LHS部分进行条件编写时并没有使用exists也可以达到判断Working Memory中是否存在某个符合条件的Fact元素的目的,那么我们使用exists还有什么意义?

两者的区别:当向Working Memory中加入多个满足条件的Fact对象时,使用了exists的规则执行一次,不使用exists的规则会执行多次。

例如:

规则文件(只有规则体):

rule "使用exists的规则"
    when
        exists Student()
    then
        System.out.println("规则:使用exists的规则触发");
end
​
rule "没有使用exists的规则"
    when
        Student()
    then
        System.out.println("规则:没有使用exists的规则触发");
end

Java代码:

kieSession.insert(new Student());
kieSession.insert(new Student());
kieSession.fireAllRules();

上面第一个规则只会执行一次,因为Working Memory中存在两个满足条件的Fact对象,第二个规则会执行两次。

4.5、规则继承

规则之间可以使用extends关键字进行规则条件部分的继承,类似于java类之间的继承。

例如:

rule "rule_1"
    when
        Student(age > 10)
    then
        System.out.println("规则:rule_1触发");
end
​
rule "rule_2" extends "rule_1" //继承上面的规则
    when
        /*
        此处的条件虽然只写了一个,但是从上面的规则继承了一个条件,
        所以当前规则存在两个条件,即Student(age < 20)和Student(age > 10)
        */
        Student(age < 20) 
    then
        System.out.println("规则:rule_2触发");
end

需要注意的是,只继承条件

5、RHS加强

RHS部分是规则体的重要组成部分,当LHS部分的条件匹配成功后,对应的RHS部分就会触发执行。一般在RHS部分中需要进行业务处理。

在RHS部分Drools为我们提供了一个内置对象,名称就是drools。

5.1、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

2、getWorkingMemory

getWorkingMemory方法的作用是返回工作内存对象。

package testgetWorkingMemory
rule "rule_getWorkingMemory"
    when
    then
        System.out.println(drools.getWorkingMemory());
end

3、getRule

getRule方法的作用是返回规则对象。

package testgetRule
rule "rule_getRule"
    when
    then
        System.out.println(drools.getRule());
end

6、规则文件编码规范

我们在进行drl类型的规则文件编写时尽量遵循如下规范:

  • 所有的规则文件(.drl)应统一放在一个规定的文件夹中,如:/rules文件夹
  • 书写的每个规则应尽量加上注释。注释要清晰明了,言简意赅
  • 同一类型的对象尽量放在一个规则文件中,如所有Student类型的对象尽量放在一个规则文件中
  • 规则结果部分(RHS)尽量不要有条件语句,如if(...),尽量不要有复杂的逻辑和深层次的嵌套语句
  • 每个规则最好都加上salience属性,明确执行顺序
  • Drools默认dialect为"Java",尽量避免使用dialect "mvel"

你可能感兴趣的:(规则引擎Drools)