做者:小傅哥
博客:https://bugstack.cn - 彙總系列專題文章
html
沉澱、分享、成長,讓本身和他人都能有所收穫! 😄
你見過這樣的代碼嘛?相似的呢?嗯,那麼恭喜你被這個世界溫柔以待!java
if else
,並非一個很是壞的關鍵字,只不過有人把他用壞了。尤爲在接到產品需求以下這樣;git
日期 | 需求 | 緊急程度 | 程序員(話外音) |
---|---|---|---|
星期一.早上 | 猿哥哥,老闆說要搞一下營銷拉拉量,給男生女生髮不一樣的優惠券,促活消費。 | 很緊急,下班就要 | 行吧,也不難,加下判斷就上線 |
星期二.下午 | 小哥哥,我們上線後很是好。要讓我們按照年輕、中年、成年,不一樣年齡加下判斷,準確刺激消費。 | 超緊急,明天就要 | 也不難,加就加吧 |
星期三.晚上 | 喂,小哥哥!睡了嗎!老闆說我們此次活動很成功,能夠不能夠在細分下,把單身、結婚、有娃的都加上不一樣判斷。這樣更能刺激用戶消費。 | 賊緊急,最快上線。 | 已經意識到ifelse 愈來愈多了 |
星期四.凌晨 | 哇!小哥哥大家太棒了,上的真快。嘻嘻!有個小請求,須要調整下年齡段,由於如今學生處對象的都比較早,有對象的更容易買某某某東西。要改下值!辛苦辛苦! | 老闆,在等着呢! | 一大片的值要修改,哎!這麼多ifelse 了 |
星期五.半夜 | 歪歪喂!巴巴,壞了,怎麼發的優惠券不對了,有客訴了,不少女生都來投訴。你快看看。老闆,他... | (一頭汗),哎,值粘錯位置了! | 終究仍是一我的扛下了全部 |
這樣的場景你是否有遇到過呢,那麼是產品給你代溝裏去了,仍是你把項目帶溝裏去了。可能會以爲,這東西這麼着急要,我也沒辦法呀。其實不止你沒有辦法,是爲了打下市場,讓每個人都很匆忙。只有合理的評估、鋪墊、架設,纔會不斷知足業務需求、產品形態的變化。不然日後的路愈來愈難!程序員
對於上面所提到的這種場景,在咱們實際開發中是常常會遇到的。尤爲是在一些;營銷、風控、人羣等,各類用戶信息決策樹關係時,都會出現這樣的業務邏輯。並且對於一些較大場景是確定不會直接硬編碼if else
,由於太難以維護。固然除非你這東西就寫一次用一次,下次不用了那無所謂。github
接下來咱們把上面的場景進行轉換一種樹結構圖,依次來體現出這個需求的全貌,以下;web
if else
你還能在本身掌握的技術棧中想到什麼解決方案嗎?接下來,咱們會寫出兩種實現方式,用做比對。@Test public void test_ifelse() { Result result = null; if ("男".equals(policy.getSex())) { if (policy.getAge() < 18) { if (policy.getUserSingle()) { result = Result.buildResult("A", "紅色A"); } else { result = Result.buildResult("B", "紅色B"); } } else if (policy.getAge() >= 18 && policy.getAge() <= 30) { if (policy.getUserMarry()) { result = Result.buildResult("C", "紅色C"); } else { result = Result.buildResult("D", "紅色D"); } } else if (policy.getAge() > 30) { if (policy.getUserParenting()) { result = Result.buildResult("E", "紅色E"); } else { result = Result.buildResult("F", "紅色F"); } } } else if ("女".equals(policy.getSex())) { if (policy.getAge() < 18) { if (policy.getUserSingle()) { result = Result.buildResult("A", "黃色A"); } else { result = Result.buildResult("B", "黃色B"); } } else if (policy.getAge() >= 18 && policy.getAge() <= 30) { if (policy.getUserMarry()) { result = Result.buildResult("C", "黃色C"); } else { result = Result.buildResult("D", "黃色D"); } } else if (policy.getAge() > 30) { if (policy.getUserParenting()) { result = Result.buildResult("E", "黃色E"); } else { result = Result.buildResult("F", "黃色F"); } } } System.out.println("決策結果(IfElse):" + result); }
if else
寫出來仍是沒問題的,只不過寫錯不錯就不必定了,畢竟一層套一層。這還算少的!關於規則引擎簡單說呢就是,將你業務邏輯中那些行爲規則流程變化的部分,分離出來。交給單獨的規則引擎進行處理。最終你只須要按照約定提供配置和入參,就能夠達到規則的執行結果。算法
Drools(JBoss Rules )具備一個易於訪問企業策略、易於調整以及易於管理的開源業務規則引擎,符合業內標準,速度快、效率高。業務分析師或審覈人員能夠利用它輕鬆查看業務規則,從而檢驗是否已編碼的規則執行了所需的業務規則。
上去就是一巴掌,而後在問爲何。好,先來把上面的代碼用Drools
處理下,以後再解釋。網絡
源碼獲取
itstack-demo-drools-02 └── src ├── main │ ├── java │ │ └── org.itstack.demo │ │ ├── model │ │ │ └── Policy.java │ │ └── Result.java │ ├── resources │ │ ├── META-INF │ │ │ └── kmodule.xml │ │ └── rules │ │ └── tree.drl │ └── webapp │ └── index.html └── test └── java └── org.itstack.demo.test └── ApiTest.java
Drools
規則引擎的的基本工程,規則引擎使用的方式並不複雜,只要按照約定的方式進行設置便可。Policy.java & 定義決策屬性,同時這也是Fact對象
public class Policy { private String sex; // 性別;男、女 private Integer age; // 年齡 private Boolean userSingle; // 單身;是/否 private Boolean userMarry; // 結婚;是/否 private Boolean userParenting; // 育兒;是/否 ...get/set }
Result.java & 定義結果輸出
public class Result { private String code; private String info; }
META-INF/kmodule.xml & 配置文件
<?xml version="1.0" encoding="utf-8" ?> <kmodule xmlns="http://www.drools.org/xsd/kmodule"> <kbase name="rules"> <ksession name="all-rules"/> </kbase> </kmodule>
kbase
,分別對應drl
的規則文件kbase name="rules"
,name名稱須要保證惟一rules/tree.drl & 規則文件
package rules; import org.itstack.demo.model.Policy import org.itstack.demo.Result; global org.itstack.demo.Result res; rule "紅A" when Policy(sex == "男", age < 18, userSingle) then res.setResult("A","紅色A"); end rule "紅B" when Policy(sex == "男", age < 18, !userSingle) then res.setResult("B","紅色B"); end rule "紅C" when Policy(sex == "男", age >= 18, age <= 30, userMarry) then res.setResult("C","紅色C"); end rule "紅D" when Policy(sex == "男", age >= 18, age <= 30, !userMarry) then res.setResult("D","紅色D"); end rule "紅E" when Policy(sex == "男", age > 30, userParenting) then res.setResult("E","紅色E"); end rule "紅F" when Policy(sex == "男", age > 30, !userParenting) then res.setResult("F","紅色F"); end rule "黃A" when Policy(sex == "女", age < 18, userSingle) then res.setResult("A","黃色A"); end rule "黃B" when Policy(sex == "女", age < 18, !userSingle) then res.setResult("B","黃色B"); end rule "黃C" when Policy(sex == "女", age >= 18, age <= 30, userMarry) then res.setResult("C","黃色C"); end rule "黃D" when Policy(sex == "女", age >= 18, age <= 30, !userMarry) then res.setResult("D","黃色D"); end rule "黃E" when Policy(sex == "女", age > 30, userParenting) then res.setResult("E","黃色E"); end rule "黃F" when Policy(sex == "女", age > 30, !userParenting) then res.setResult("F","黃色F"); end
sex == "女", age > 30, !userParenting
,英文逗號隔開的是and的條件,至關你的且。當不徹底是,由於在後續處理中,逗號的處理邏輯在drools是有優化的。global
全局引入。最後結尾end關鍵字。if else
嗎。但千萬不要這麼以爲,由於這只是冰山一角。並且咱們前面截圖一個樹形結構,而這個屬性結構是能夠自動化生成DRL
規則文件的。ApiTest.java & 單元測試中會設置Drools的啓動過程
public class ApiTest { private KieContainer kieContainer; private Policy policy; @Before public void init() { // 構建KieServices KieServices kieServices = KieServices.Factory.get(); kieContainer = kieServices.getKieClasspathContainer(); policy = new Policy(); policy.setSex("男"); policy.setAge(16); policy.setUserSingle(false); policy.setUserMarry(false); policy.setUserParenting(false); System.out.println("決策請求:" + JSON.toJSONString(policy)); } @Test public void test_drools() { KieSession kieSession = kieContainer.newKieSession("all-rules"); kieSession.insert(policy); Result result = new Result(); kieSession.setGlobal("res", result); int count = kieSession.fireAllRules(); System.out.println("Fire rule(s):" + count); System.out.println("決策結果(Drools):" + result); kieSession.dispose(); } }
init() 初始化session
KieServices.Factory.get();
,這個過程是比較耗費資源,實際業務使用中也不會頻繁的構建。KieServices
中獲取KieContainer
,用於給定KieModule的全部kiebase的容器。test_drools() 執行規則app
kieSession.insert(policy);
kieSession.setGlobal("res", result);
,用於最終把結果輸出kieSession.fireAllRules()
kieSession.dispose()
測試結果
決策請求:{"age":16,"sex":"男","userMarry":false,"userParenting":false,"userSingle":false} Fire rule(s):1 決策結果(Drools):B|紅色B
Drools 是用 Java 語言編寫的開放源碼規則引擎,使用 Rete 算法對所編寫的規則求值。Drools 容許使用聲明方式表達業務邏輯。可使用非 XML 的本地語言編寫規則,從而便於學習和理解。而且,還能夠將 Java 代碼直接嵌入到規則文件中,這令 Drools 的學習更加吸引人。
好!那麼這樣你就知道,Drools的核心內容是關於 Rete 算法的實現。接下來咱們再來了解下 Rete。
爲了解決生產式推理引擎效率底下的問題,Forgy 在1979年提出 Rete 算法,做爲生產式系統的高效模式匹配算法。Rete 算法的初衷是:利用規則之間各個域的公用部分減小規則存儲,同時保存匹配過程的臨時結果以加快匹配速度。爲了達到這種效果,算法將規則拆分,其中每一個條件單元做爲基本單位(節點)鏈接成一個數據辨別網絡,而後將事實通過網絡篩選並傳播,最終全部條件都有事實匹配的規則被激活。
Rete 算法自從 1979 年提出以來,已經經歷過各類改進與推廣。除了對自身規則網絡結構的優化外,對一些功能擴展如模糊推理、事件推理、並行化等也有不少研究。
邏輯操做符(operators)是指注入and、or、not等,的邏輯運算符處理。
規則前件順序是指規則體哦啊見中的各個約束的排列順序,它決定了條件連接操做的執行順序,影響中間結果的大小,是決定規則匹配效率的關鍵因素。
索引方法是指對 Rete 網絡的節點創建當前節點對後繼 的索引,在事實斷言時能夠經過索引快速找到對應的後繼節 點而無需逐個查找。
瑕疵數據與不肯定性推理
除了數據瑕疵,對於變化劇烈的數據也成爲Rete算法須要解決的問題。
Rete 算法從提出至今,性能提高問題一直是研究重點。多核多處理器問世後,將推理過程分配到不一樣機器上並行處理成爲一種常見的效率提高方法
若是你控制不住本身,就會有別人控制你
CodeGuide | 程序員編碼指南 Go!
https://github.com/fuzhengwei/CodeGuide/wiki
本代碼庫是做者小傅哥多年從事一線互聯網 Java 開發的學習歷程技術彙總,旨在爲你們提供一個清晰詳細的學習教程,側重點更傾向編寫Java核心內容。若是本倉庫能爲您提供幫助,請給予支持(關注、點贊、分享)!