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