目錄
- 6. Drools高級語法
- 6.1 global全域變數
- 6.2 query查詢
- 6.3 function函式
- 6.4 LHS加強
- 6.4.1 復合值限制in/not in
- 6.4.2 條件元素eval
- 6.4.3 條件元素not
- 6.4.4 條件元素exists
- 6.4.5 規則繼承
- 6.5 RHS加強
- 6.5.1 halt
- 6.5.2 getWorkingMemory
- 6.5.3 getRule
- 6.6 規則檔案編碼規范
- 6.7 以上代碼均在drools_quickstart專案中
6. Drools高級語法
全套代碼及資料全部完整提供,點此處下載
前面章節我們已經知道了一套完整的規則檔案內容構成如下:
| 關鍵字 | 描述 |
|---|---|
| package | 包名,只限于邏輯上的管理,同一個包名下的查詢或者函式可以直接呼叫 |
| import | 用于匯入類或者靜態方法 |
| global | 全域變數 |
| function | 自定義函式 |
| query | 查詢 |
| rule end | 規則體 |
本章節我們就來學習其中的幾個關鍵字,
6.1 global全域變數
global關鍵字用于在規則檔案中定義全域變數,它可以讓應用程式的物件在規則檔案中能夠被訪問,可以用來為規則檔案提供資料或服務,
語法結構為:global 物件型別 物件名稱
在使用global定義的全域變數時有兩點需要注意:
1、如果物件型別為包裝型別時,在一個規則中改變了global的值,那么只針對當前規則有效,對其他規則中的global不會有影響,可以理解為它是當前規則代碼中的global副本,規則內部修改不會影響全域的使用,
2、如果物件型別為集合型別或JavaBean時,在一個規則中改變了global的值,對java代碼和所有規則都有效,
下面我們通過代碼進行驗證:
第一步:創建UserService類
package com.itheima.drools.service;
public class UserService {
public void save(){
System.out.println("UserService.save()...");
}
}
第二步:撰寫規則檔案/resources/rules/global.drl
package testglobal
/*
此規則檔案用于測驗global全域變數
*/
global java.lang.Integer count //定義一個包裝型別的全域變數
global com.itheima.drools.service.UserService userService //定義一個JavaBean型別的全域變數
global java.util.List gList //定義一個集合型別的全域變數
rule "rule_global_1"
when
then
count += 10; //全域變數計算,只對當前規則有效,其他規則不受影響
userService.save();//呼叫全域變數的方法
gList.add("itcast");//向集合型別的全域變數中添加元素,Java代碼和所有規則都受影響
gList.add("itheima");
System.out.println("count=" + count);
System.out.println("gList.size=" + gList.size());
end
rule "rule_global_2"
when
then
userService.save();
System.out.println("count=" + count);
System.out.println("gList.size=" + gList.size());
end
第三步:撰寫單元測驗
KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();
//設定全域變數,名稱和型別必須和規則檔案中定義的全域變數名稱對應
kieSession.setGlobal("userService",new UserService());
kieSession.setGlobal("count",5);
List list = new ArrayList();//size為0
kieSession.setGlobal("gList",list);
kieSession.fireAllRules();
kieSession.dispose();
//因為在規則中為全域變數添加了兩個元素,所以現在的size為2
System.out.println(list.size());
6.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用于查詢Working Memory中age>10同時name需要和傳遞的引數name相同的Student物件
query "query_2"(String sname)
$student:Student(age > 20 && name == sname)
end
第二步:撰寫單元測驗
KieServices kieServices = KieServices.Factory.get();
KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieClasspathContainer.newKieSession();
Student student1 = new Student();
student1.setName("張三");
student1.setAge(12);
Student student2 = new Student();
student2.setName("李四");
student2.setAge(8);
Student student3 = new Student();
student3.setName("王五");
student3.setAge(22);
//將物件插入Working Memory中
kieSession.insert(student1);
kieSession.insert(student2);
kieSession.insert(student3);
//呼叫規則檔案中的查詢
QueryResults results1 = kieSession.getQueryResults("query_1");
int size = results1.size();
System.out.println("size=" + size);
for (QueryResultsRow row : results1) {
Student student = (Student) row.get("$student");
System.out.println(student);
}
//呼叫規則檔案中的查詢
QueryResults results2 = kieSession.getQueryResults("query_2","王五");
size = results2.size();
System.out.println("size=" + size);
for (QueryResultsRow row : results2) {
Student student = (Student) row.get("$student");
System.out.println(student);
}
//kieSession.fireAllRules();
kieSession.dispose();
6.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("小明");
kieSession.insert(student);
kieSession.fireAllRules();
kieSession.dispose();
6.4 LHS加強
前面我們已經知道了在規則體中的LHS部分是介于when和then之間的部分,主要用于模式匹配,只有匹配結果為true時,才會觸發RHS部分的執行,本章節我們會針對LHS部分學習幾個新的用法,
6.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 ("張三","李四","王五"))
6.4.2 條件元素eval
eval用于規則體的LHS部分,并回傳一個Boolean型別的值,語法結構如下:
eval(運算式)
舉例:
eval(true)
eval(false)
eval(1 == 1)
6.4.3 條件元素not
not用于判斷Working Memory中是否存在某個Fact物件,如果不存在則回傳true,如果存在則回傳false,語法結構如下:
not Object(可選屬性約束)
舉例:
not Student()
not Student(age < 10)
6.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物件,第二個規則會執行兩次,
6.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
6.5 RHS加強
RHS部分是規則體的重要組成部分,當LHS部分的條件匹配成功后,對應的RHS部分就會觸發執行,一般在RHS部分中需要進行業務處理,
在RHS部分Drools為我們提供了一個內置物件,名稱就是drools,本小節我們來介紹幾個drools物件提供的方法,
6.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
6.5.2 getWorkingMemory
getWorkingMemory方法的作用是回傳作業記憶體物件,
package testgetWorkingMemory
rule "rule_getWorkingMemory"
when
then
System.out.println(drools.getWorkingMemory());
end
6.5.3 getRule
getRule方法的作用是回傳規則物件,
package testgetRule
rule "rule_getRule"
when
then
System.out.println(drools.getRule());
end
6.6 規則檔案編碼規范
我們在進行drl型別的規則檔案撰寫時盡量遵循如下規范:
- 所有的規則檔案(.drl)應統一放在一個規定的檔案夾中,如:/rules檔案夾
- 書寫的每個規則應盡量加上注釋,注釋要清晰明了,言簡意賅
- 同一型別的物件盡量放在一個規則檔案中,如所有Student型別的物件盡量放在一個規則檔案中
- 規則結果部分(RHS)盡量不要有條件陳述句,如if(...),盡量不要有復雜的邏輯和深層次的嵌套陳述句
- 每個規則最好都加上salience屬性,明確執行順序
- Drools默認dialect為"Java",盡量避免使用dialect "mvel"
6.7 以上代碼均在drools_quickstart專案中
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/538422.html
標籤:Java
上一篇:二進制列舉(一)
