簡書著作權歸作者所有秒咨,任何形式的轉載都請聯(lián)系作者獲得授權并注明出處但骨。
? ? ? ?在上一篇文章中創(chuàng)建規(guī)則引擎時道逗,用的是如下語句:
RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(true);
RulesEngine fizzBuzzEngine = new DefaultRulesEngine(parameters);
? ? ? ?這里為規(guī)則引擎設置了一個屬性skipOnFirstAppliedRule砂沛,除了這一個屬性之外,規(guī)則引擎還有另外三個屬性哀澈,也就是說它一共有四個屬性牌借,即 rulePriorityThreshold、skipOnFirstAppliedRule割按、skipOnFirstFailedRule 和 skipOnFirstNonTriggeredRule走哺。其中 skipOnFirstFailedRule 屬性平時用到的比較少,因此我們這里不再贅述哲虾。下面我們通過實例來演示一下其他三個屬性的作用丙躏。
一、使用實例
? ? ? ?假設我們有這樣一個場景:
? ? (1)如果一個數(shù)字可以被 3 整除束凑,則輸出“three”晒旅;
? ? (2)如果一個數(shù)字在不滿足上面條件的情況下可以被 5 整除,則輸出“five”汪诉;
? ? (3)如果一個數(shù)字在均不滿足上面兩個條件的情況下可以被 7 整除废恋,則輸出“seven”;
? ? (4)如果一個數(shù)字均不滿足上述條件扒寄,則輸出該數(shù)字本身鱼鼓。
二、規(guī)則文件的文件名為 rules.yml 该编,其內(nèi)容如下:
---
name: "three"
description: "print three"
priority: 0
condition: "number % 3 == 0"
actions:
- "System.out.println(\"three\")"
---
name: "five"
description: "print five"
priority: 1
condition: "number % 5 == 0"
actions:
- "System.out.println(\"five\")"
---
name: "seven"
description: "print seven"
priority: 2
condition: "number % 7 == 0"
actions:
- "System.out.println(\"seven\")"
---
name: "itself"
description: "print the number itself otherwise"
priority: 3
condition: "true"
actions:
- "System.out.println(number)"
1迄本、客戶端調(diào)用代碼——不設置任何屬性的規(guī)則引擎
public class RuleClient {
public static void main(String[] args) throws FileNotFoundException {
RulesEngine rulesEngine = new DefaultRulesEngine();
Rules rules = MVELRuleFactory.createRulesFrom(new FileReader("rules.yml"));
Facts facts = new Facts();
for (int i = 1; i <= 20; i++) {
System.out.println("====== " + i + " ======");
facts.put("number", i);
rulesEngine.fire(rules, facts);
}
}
}
執(zhí)行結果如下:
====== 1 ======
1
====== 2 ======
2
====== 3 ======
three
3
====== 4 ======
4
====== 5 ======
five
5
====== 6 ======
three
6
====== 7 ======
seven
7
====== 8 ======
8
====== 9 ======
three
9
====== 10 ======
five
10
====== 11 ======
11
====== 12 ======
three
12
====== 13 ======
13
====== 14 ======
seven
14
====== 15 ======
three
five
15
====== 16 ======
16
====== 17 ======
17
====== 18 ======
three
18
====== 19 ======
19
====== 20 ======
five
20
過程分析:
? ? ? ?由于在創(chuàng)建規(guī)則引擎時沒有給其設置任何屬性,所以客戶端中每一個被 put 到 Facts 中的 number 都會對 .yml 文件中定義的所有規(guī)則按照優(yōu)先級從高到低的順序(priority的值越小课竣,則相應規(guī)則的優(yōu)先級越高)進行判斷嘉赎,并決定是否執(zhí)行相應的操作。
? ? ? ?比如于樟,數(shù)字 1 對于 .yml 文件中的所有規(guī)則按照優(yōu)先級從高到低的順序進行判斷公条,發(fā)現(xiàn)只滿足 priority 為 3 的那條規(guī)則,因此輸出了數(shù)字 1 本身迂曲。
? ? ? ?又比如靶橱,數(shù)字 15 滿足 priority 為 0 的那條規(guī)則,因此輸出了 “three”路捧,同時數(shù)字 15 還滿足 priority 為 1 的那條規(guī)則关霸,因此又輸出了 “five”,同時數(shù)字 15 還滿足 priority 為 3 的規(guī)則鬓长,因此還輸出了數(shù)字 15 本身谒拴。
2、客戶端調(diào)用代碼——設置了 skipOnFirstAppliedRule 屬性的規(guī)則引擎
public class RuleClient {
public static void main(String[] args) throws FileNotFoundException {
RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(true);
RulesEngine rulesEngine = new DefaultRulesEngine(parameters);
Rules rules = MVELRuleFactory.createRulesFrom(new FileReader("rules.yml"));
Facts facts = new Facts();
for (int i = 1; i <= 20; i++) {
System.out.println("====== " + i + " ======");
facts.put("number", i);
rulesEngine.fire(rules, facts);
}
}
}
執(zhí)行結果如下:
====== 1 ======
1
====== 2 ======
2
====== 3 ======
three
====== 4 ======
4
====== 5 ======
five
====== 6 ======
three
====== 7 ======
seven
====== 8 ======
8
====== 9 ======
three
====== 10 ======
five
====== 11 ======
11
====== 12 ======
three
====== 13 ======
13
====== 14 ======
seven
====== 15 ======
three
====== 16 ======
16
====== 17 ======
17
====== 18 ======
three
====== 19 ======
19
====== 20 ======
five
過程分析:
? ? ? ?skipOnFirstAppliedRule 屬性的作用是涉波,客戶端中每一個被 put 到 Facts 中的 number 都會對 .yml 文件中定義的所有規(guī)則按照優(yōu)先級從高到低的順序進行判斷英上,當發(fā)現(xiàn)一個滿足條件的規(guī)則并執(zhí)行了相關操作后,便不再繼續(xù)判斷其他規(guī)則啤覆。如數(shù)字 10苍日,先對 priority 為 0 的規(guī)則進行判斷,發(fā)現(xiàn)不滿足該規(guī)則的條件窗声,于是繼續(xù)判斷 priority 為 1 的規(guī)則相恃,發(fā)現(xiàn)滿足該規(guī)則的條件,于是輸出“five”笨觅。至此拦耐,數(shù)字 10 便不會在理會 priority 為 2 和 priority 為 3 的規(guī)則耕腾,因此對于數(shù)字 10,其只輸出了“five”杀糯。
3扫俺、客戶端調(diào)用代碼——設置了 skipOnFirstNonTriggeredRule 屬性的規(guī)則引擎
public class RuleClient {
public static void main(String[] args) throws FileNotFoundException {
RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstNonTriggeredRule(true);
RulesEngine rulesEngine = new DefaultRulesEngine(parameters);
Rules rules = MVELRuleFactory.createRulesFrom(new FileReader("rules.yml"));
Facts facts = new Facts();
for (int i = 1; i <= 20; i++) {
System.out.println("====== " + i + " ======");
facts.put("number", i);
rulesEngine.fire(rules, facts);
}
}
}
執(zhí)行結果如下:
====== 1 ======
====== 2 ======
====== 3 ======
three
====== 4 ======
====== 5 ======
====== 6 ======
three
====== 7 ======
====== 8 ======
====== 9 ======
three
====== 10 ======
====== 11 ======
====== 12 ======
three
====== 13 ======
====== 14 ======
====== 15 ======
three
five
====== 16 ======
====== 17 ======
====== 18 ======
three
====== 19 ======
====== 20 ======
過程分析:
? ? ? ?skipOnFirstNonTriggeredRule 屬性的作用是,客戶端中每一個被 put 到 Facts 中的 number 都會對 .yml 文件中定義的所有規(guī)則按照優(yōu)先級從高到低的順序進行判斷固翰,如果滿足當前的規(guī)則狼纬,則執(zhí)行相應的操作,直到遇到不滿足條件的規(guī)則為止骂际,并且也不會對其他規(guī)則進行判斷了疗琉。我們?nèi)匀灰詳?shù)字 15 為例說明一下,數(shù)字 15 對 .yml 文件中的所有規(guī)則按照優(yōu)先級從高到低的順序進行判斷歉铝,發(fā)現(xiàn)滿足 priority 為 0 和 priority 為 1 的兩個規(guī)則盈简,于是輸出了“three”和“five”,在接下來判斷 priority 為 2 的規(guī)則時犯戏,發(fā)現(xiàn)數(shù)字 15 并不滿足這條規(guī)則送火,于是不做任何操作,至此先匪,數(shù)字 15 也不會再理會 priority 為 3 的規(guī)則了种吸。
3、客戶端調(diào)用代碼——設置了 rulePriorityThreshold 屬性的規(guī)則引擎
public class RuleClient {
public static void main(String[] args) throws FileNotFoundException {
RulesEngineParameters parameters = new RulesEngineParameters().priorityThreshold(1);
RulesEngine rulesEngine = new DefaultRulesEngine(parameters);
Rules rules = MVELRuleFactory.createRulesFrom(new FileReader("rules.yml"));
Facts facts = new Facts();
for (int i = 1; i <= 20; i++) {
System.out.println("====== " + i + " ======");
facts.put("number", i);
rulesEngine.fire(rules, facts);
}
}
}
執(zhí)行結果如下:
====== 1 ======
====== 2 ======
====== 3 ======
three
====== 4 ======
====== 5 ======
five
====== 6 ======
three
====== 7 ======
====== 8 ======
====== 9 ======
three
====== 10 ======
five
====== 11 ======
====== 12 ======
three
====== 13 ======
====== 14 ======
====== 15 ======
three
five
====== 16 ======
====== 17 ======
====== 18 ======
three
====== 19 ======
====== 20 ======
five
過程分析:
? ? ? ?在創(chuàng)建規(guī)則引擎時呀非,我們將其屬性 rulePriorityThreshold 的值設置為了 1坚俗,這樣的設置后的效果相當于在定義的所有規(guī)則中將 priority > 1 的規(guī)則去掉,換種說法就是只考慮 priority 的值小于等于 1 的規(guī)則岸裙。
三猖败、決定將規(guī)則放在 .java 文件還是 .yml 文件中的一些建議
? ? ? ?從上一章的介紹中我們知道規(guī)則可以以 .java 文件或 .yml 文件的形式出現(xiàn),但選用哪種文件比較合適降允,我這里有些個人建議:
? ?(1)若將規(guī)則放在 .java 文件中恩闻,我們可以在 @Condition 模塊進行比較復雜的邏輯編程,然后返回 true 或 false 來決定是否執(zhí)行 @Action 模塊的操作剧董,同時如果需要幢尚,我們也可以很方便地在 @Action 模塊實現(xiàn)比較復雜的邏輯。所以翅楼,如果涉及比較復雜的邏輯推導時尉剩,我們選用將規(guī)則放入 .java 文件中可以在該 .java 文件中使用我們較為熟悉的 java 語言來進行相關的邏輯推導。但將這種復雜的邏輯放到 .yml 文件中去實現(xiàn)的話毅臊,對于經(jīng)驗不是很豐富的人員來說可能是一種折磨鸟悴。
? ?(2)若在業(yè)務邏輯中只需要通過簡單地判斷就能得出相應的布爾值狂丝,且 Action 模塊的邏輯也比較簡單的話稍走,可以考慮將這些規(guī)則放入 .yml 文件中,這樣可以使得規(guī)則文件的內(nèi)容更加緊湊和明了朗鸠。
注意:以上建議僅供參考,具體選擇哪種方式以實際的應用場景為準來選擇式撼。
補充:
? ?? ?1童社、在規(guī)則文件中,不同的規(guī)則也可以設置相同的優(yōu)先級著隆,這是語法允許的。
? ?? ?2呀癣、在創(chuàng)建規(guī)則引擎并為其設置屬性時美浦,可以同時設置多個,例如:
RulesEngineParameters parameters = new RulesEngineParameters()
.priorityThreshold(10)
.skipOnFirstAppliedRule(true)
.skipOnFirstFailedRule(true)
.skipOnFirstNonTriggeredRule(true);
RulesEngine rulesEngine = new DefaultRulesEngine(parameters);
? ?? ?3项栏、在設置了規(guī)則引擎的屬性后浦辨,在程序接下來的某個階段如果需要改變該引擎的屬性,可以先得到該引擎的屬性沼沈,然后再重新設置屬性值流酬。得到規(guī)則引擎屬性的方式如下:
RulesEngineParameters parameters = myEngine.getParameters();