Drools规则引擎技术指南
上QQ阅读APP看书,第一时间看更新

3.6 语法扩展

规则中的集合处理遇到集合应该怎样获取它们的元素呢?下面针对List、Map、Set展开说明。

1. List元素操作

创建规则文件collection.drl,目录为rules/constraint/isCollection,并添加如下代码:

package rules.constraint.isCollection;

import com.pojo.Person;
import com.pojo.School;

rule collectionTestList
    when
        $s:School();
    then
      System.out.println("School属性classNameList的第二个元素为"+$s.
getClassNameList().get(1));
end

修改kmodule.xml配置文件,并添加如下配置:

<kbase name="collection" packages="rules.constraint.isCollection">
    <ksession name="collection"/>
</kbase>

创建执行调用规则文件rulesCollection.java,其代码为:

package com.rulesConstraint;

import com.pojo.Person;
import com.pojo.School;
import org.junit.Test;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

import java.util.*;

public class RulesCollection {
    @Test
    public void testList() {
        KieServices kss = KieServices.Factory.get();
        KieContainer kc = kss.getKieClasspathContainer();
        KieSession ks = kc.newKieSession("collection");
        Person person = new Person();
        person.setName("张三");
        person.setAge(30);
        person.setClassName("一班");
        School school = new School();
        List list=new ArrayList();
        list.add("一班");
        list.add("二班");
        list.add("三班");
        school.setClassNameList(list);
        ks.insert(person);
        ks.insert(school);
        int count = ks.fireAllRules();
        System.out.println("总执行了" + count + "条规则");
        ks.dispose();
    }
}

运行testList()方法,结果如图3-19所示。

059-1

图3-19 List在then中的使用

第二种写法是通过属性名直接引用,但使用元素需要通过“[]”来调用。添加规则文件collectionTestList2,其代码为:

rule collectionTestList2
    when
        $s:School(classNameList[1]=="二班");
    then
      System.out.println("规则 collectionTestList2   School属性
classNameList的第二个元素为"+$s.getClassNameList().get(1));
end

运行testList()方法,结果如图3-20所示。

059-2

图3-20 规则中List的第二种用法

List语法使用总结:classNameList[1]与$s.getClassNameList().get(1)是相同的,但classNameList[1]方式只能在LHS部分使用,$s.getClassNameList()方式只能在RHS部分使用,且操作不当可能会出现异常情况。

2. Set元素操作

编辑规则文件collection.drl,并添加规则collectionTestSet,其代码为:

rule collectionTestSet
    when
        $s:School();
    then
      System.out.println("School属性classNameSet的第一个元素为"+$s.getClassNameSet().iterator().next());
end

编辑执行调用规则testList()方法,其代码为:

@Test
public void testList() {
    KieServices kss = KieServices.Factory.get();
    KieContainer kc = kss.getKieClasspathContainer();
    KieSession ks = kc.newKieSession("collection");
    Person person = new Person();
    person.setName("张三");
    person.setAge(30);
    person.setClassName("一班");
    School school = new School();
    List list=new ArrayList();
    list.add("一班");
    list.add("二班");
    list.add("三班");
    school.setClassNameList(list);
    Set classNameSet = new HashSet();
    classNameSet.add("一班");
    classNameSet.add("二班");
    classNameSet.add("三班");
    school.setClassNameSet(classNameSet);
    ks.insert(person);
    ks.insert(school);
    int count = ks.fireAllRules();
    System.out.println("总执行了" + count + "条规则");
    ks.dispose();
}

关注加粗部分,并执行testList()方法,结果如图3-21所示。

061-1

图3-21 Set集合元素操作

Set集合元素操作是否也有与List相似的功能呢?在规则体LHS部分获取Set元素,编辑collection.drl规则文件,并添加collectionTestSet2规则,其代码为:

rule collectionTestSet2
    when
        $s:School(classNameSet.iterator().next=="一班");
    then
      System.out.println("规则 collectionTestSet2 School属性classNameSet的第一个元素为"+$s.getClassNameSet().iterator().next());
end

再次执行testList()方法,结果提示语法错误,使用from遍历Set集合结果也一样。由此得出结论:使用Set时只能通过RHS部分,就像是Java写法一样。

3. Map元素操作

编辑规则文件collection.drl,并添加规则collectionTestMap,其代码为:

rule collectionTestMap
    when
        $s:School();
    then
      System.out.println("School属性classNameMap的元素Key为一班的值"+$s.getClassNameMap().get("一班"));
end

编辑执行调用规则testList()方法,其代码为:

@Test
public void testList() {
    KieServices kss = KieServices.Factory.get();
    KieContainer kc = kss.getKieClasspathContainer();
    KieSession ks = kc.newKieSession("collection");
    Person person = new Person();
    person.setName("张三");
    person.setAge(30);
    person.setClassName("一班");
    School school = new School();
    List list=new ArrayList();
    list.add("一班");
    list.add("二班");
    list.add("三班");
    school.setClassNameList(list);
    Set classNameSet = new HashSet();
    classNameSet.add("一班");
    classNameSet.add("二班");
    classNameSet.add("三班");
    school.setClassNameSet(classNameSet);
    Map classNameMap = new HashMap();
    classNameMap.put("一班","1");
    classNameMap.put("二班","2");
    classNameMap.put("三班","3");
    school.setClassNameMap(classNameMap);
    ks.insert(person);
    ks.insert(school);
    int count = ks.fireAllRules();
    System.out.println("总执行了" + count + "条规则");
    ks.dispose();

关注加粗部分,并执行testList()方法,结果如图3-22所示。

062-1

图3-22 Map元素操作

Map元素操作是否也有与List相似的功能呢?在规则体LHS部分获取Map元素,编辑collection.drl规则文件,并添加collectionTestMap2规则,其代码为:

rule collectionTestMap2
  when
      $s:School(classNameMap.get("一班")=="1");
  then
    System.out.println("规则 collectionTestMap2 School属性classNameMap的元素Key为一班的值"+$s.getClassNameMap().get("一班"));
end

执行testList()方法,结果如图3-23所示。

062-2

图3-23 Map元素在规则LHS的部分操作

Map语法使用总结:classNameMap.get(key)与$s.getClassNameMap().get("key")是相同的,但classNameMap.get(key)方式只能在LHS部分使用,$s.getClassNameMap().get("key")只能在RHS部分使用。

在上述操作集合的例子中,是通过JavaBean的属性进行传值的,如果直接insert List、Set、Map是否可行呢?

4. List集合测试

创建规则文件collectionInsert.drl,目录为rules/constraint/isCollection/insert,并添加如下代码:

package rules.constraint.isCollection.isinsert;

import com.pojo.School;
import com.pojo.Person;
import java.util.List;

rule collectionTestList
    when
       $l:List();
    then
    System.out.println("输出List第二个元素内容为"+$l.get(1));
end

修改kmodule.xml配置文件,并添加如下配置:

<kbase name="collectionInsert" packages="rules.constraint.isCollection.insert">
    <ksession name="collectionInsert"/>
</kbase>

编辑RulesCollection.java文件,并添加testInsertList()方法,其代码为:

@Test
public void testInsertList() {
    KieServices kss = KieServices.Factory.get();
    KieContainer kc = kss.getKieClasspathContainer();
    KieSession ks = kc.newKieSession("collectionInsert ");
    Person person = new Person();
    person.setName("张三");
    person.setAge(30);
    person.setClassName("一班");
    School school = new School();
    List list=new ArrayList();
    list.add("一班");
    list.add("二班");
    list.add("三班");
    ks.insert(list);
    ks.insert(school);
    int count = ks.fireAllRules();
    System.out.println("总执行了" + count + "条规则");
    ks.dispose();
}

执行testInsertList()方法,结果如图3-24所示。

064-1

图3-24 List集合测试结果

虽然结果输出是正确的,但实际操作中肯定不会这样简单,因此提出了3个问题:第一,如何遍历insert(list)这个特殊的Fact对象;第二,如果同时insert两个List对象,规则又应该如何识别呢;第三,如何在LHS部分使用List。针对这3个问题做如下说明:第一个问题,遍历List有两种方式,一种是在RHS部分通过Java代码进行遍历,另一种则是通过from[4]进行遍历;第二个问题,如果同时insert两个List,规则会被激活两次,insert的优先级以最后一次使用insert的参数做第一次匹配,包括同时insert的多个对象;第三个问题,使用Set、Map实验完成后再给出总结。

5. Set、Map进行测试

修改规则文件collectionInsert.drl,并添加collectionTestSet及collectionTestMap规则,其内容为:

rule collectionTestSet
     when
        $s:Set();
     then
     System.out.println("输出Set第一个元素内容为"+$s.iterator().next());
 end

 rule collectionTestMap
      when
         $m:Map();
      then
     System.out.println("输出Map的元素Key为一班的值"+$m.get("一班"));
  end

修改testInsertList方法,其内容为:

@Test
public void testInsertList() {
    KieServices kss = KieServices.Factory.get();
    KieContainer kc = kss.getKieClasspathContainer();
    KieSession ks = kc.newKieSession("collectionInsert");
    Person person = new Person();
    person.setName("张三");
    person.setAge(30);
    person.setClassName("一班");
    School school = new School();
    List list=new ArrayList();
    list.add("一班");
    list.add("二班");
    list.add("三班");
    school.setClassNameList(list);
    Set classNameSet = new HashSet();
    classNameSet.add("一班");
    classNameSet.add("二班");
    classNameSet.add("三班");
    Map classNameMap = new HashMap();
    classNameMap.put("一班","1");
    classNameMap.put("二班","2");
    classNameMap.put("三班","3");
    ks.insert(list);
    ks.insert(classNameSet);
    ks.insert(classNameMap);
    int count = ks.fireAllRules();
    System.out.println("总执行了" + count + "条规则");
    ks.dispose();
}

执行testInsertList()方法,结果如图3-25所示。

065-1

图3-25 Set、Map测试结果

通过图3-25所示结果,得出第三个问题的答案,List、Set、Map如果单独被insert操作,在规则体LHS部分的使用与JavaBean中的成员变量操作集合基本相似。