日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Drools规则引擎入门小demo

發(fā)布時間:2023/12/10 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Drools规则引擎入门小demo 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1. 問題引出

現(xiàn)有一個在線申請信用卡的業(yè)務(wù)場景,用戶需要錄入個人信息,如下圖所示:

通過上圖可以看到,用戶錄入的個人信息包括姓名、性別、年齡、學(xué)歷、電話、所在公司、職位、月收入、是否有房、是否有車、是否有信用卡等。錄入完成后點(diǎn)擊申請按鈕提交即可。

用戶提交申請后,需要在系統(tǒng)的服務(wù)端進(jìn)行用戶信息合法性檢查(是否有資格申請信用卡),只有通過合法性檢查的用戶才可以成功申請到信用卡(注意:不同用戶有可能申請到的信用卡額度不同)。

檢查用戶信息合法性的規(guī)則如下:

規(guī)則編號名稱描述
1檢查學(xué)歷與薪水1如果申請人既沒房也沒車,同時學(xué)歷為大專以下,并且月薪少于5000,那么不通過
2檢查學(xué)歷與薪水2如果申請人既沒房也沒車,同時學(xué)歷為大專或本科,并且月薪少于3000,那么不通過
3檢查學(xué)歷與薪水3如果申請人既沒房也沒車,同時學(xué)歷為本科以上,并且月薪少于2000,同時之前沒有信用卡的,那么不通過
4檢查申請人已有的信用卡數(shù)量如果申請人現(xiàn)有的信用卡數(shù)量大于10,那么不通過

用戶信息合法性檢查通過后,還需要根據(jù)如下信用卡發(fā)放規(guī)則確定用戶所辦信用卡的額度:

規(guī)則編號名稱描述
1規(guī)則1如果申請人有房有車,或者月收入在20000以上,那么發(fā)放的信用卡額度為15000
2規(guī)則2如果申請人沒房沒車,但月收入在10000~20000之間,那么發(fā)放的信用卡額度為6000
3規(guī)則3如果申請人沒房沒車,月收入在10000以下,那么發(fā)放的信用卡額度為3000
4規(guī)則4如果申請人有房沒車或者沒房但有車,月收入在10000以下,那么發(fā)放的信用卡額度為5000
5規(guī)則5如果申請人有房沒車或者是沒房但有車,月收入在10000~20000之間,那么發(fā)放的信用卡額度為8000

思考:如何實現(xiàn)上面的業(yè)務(wù)邏輯呢?

我們最容易想到的就是使用分支判斷(if else)來實現(xiàn),例如通過如下代碼來檢查用戶信息合法性:

//此處為偽代碼//檢查用戶信息合法性,返回true表示檢查通過,返回false表示檢查不通過 public boolean checkUser(User user){//如果申請人既沒房也沒車,同時學(xué)歷為大專以下,并且月薪少于5000,那么不通過if(user.getHouse() == null && user.getcar() == null && user.getEducation().equals("大專以下") && user.getSalary < 5000){return false;}//如果申請人既沒房也沒車,同時學(xué)歷為大專或本科,并且月薪少于3000,那么不通過else if(user.getHouse() == null && user.getcar() == null && user.getEducation().equals("大專或本科") && user.getSalary < 3000){return false;}//如果申請人既沒房也沒車,同時學(xué)歷為本科以上,并且月薪少于2000,同時之前沒有信用卡的,那么不通過else if(user.getHouse() == null && user.getcar() == null && user.getEducation().equals("本科以上") && user.getSalary < 2000 && user.getHasCreditCard() == false){return false;}//如果申請人現(xiàn)有的信用卡數(shù)量大于10,那么不通過else if(user.getCreditCardCount() > 10){return false;}return true; }

如果用戶信息合法性檢查通過后,還需要通過如下代碼確定用戶所辦信用卡的額度:

//此處為偽代碼//根據(jù)用戶輸入信息確定信用卡額度 public Integer determineCreditCardLimit(User user){//如果申請人有房有車,或者月收入在20000以上,那么發(fā)放的信用卡額度為15000if((user.getHouse() != null && user.getcar() != null) || user.getSalary() > 20000){return 15000;}//如果申請人沒房沒車,并且月收入在10000到20000之間,那么發(fā)放的信用卡額度為6000else if(user.getHouse() == null && user.getcar() == null&& user.getSalary() > 10000 && user.getSalary() < 20000){return 6000;}//如果申請人沒房沒車,并且月收入在10000以下,那么發(fā)放的信用卡額度為3000else if(user.getHouse() == null && user.getcar() == null&& user.getSalary() < 10000){return 3000;}//如果申請人有房沒車或者沒房但有車,并且月收入在10000以下,那么發(fā)放的信用卡額度為5000else if((((user.getHouse() != null && user.getcar() == null) || (user.getHouse() == null && user.getcar() != null))&& user.getSalary() < 10000){return 5000;}//如果申請人有房沒車或者沒房但有車,并且月收入在10000到20000之間,那么發(fā)放的信用卡額度為8000else if((((user.getHouse() != null && user.getcar() == null) || (user.getHouse() == null && user.getcar() != null))&& (user.getSalary() > 10000 && user.getSalary() < 20000)){return 8000;} }

通過上面的偽代碼我們可以看到,我們的業(yè)務(wù)規(guī)則是通過Java代碼的方式實現(xiàn)的。這種實現(xiàn)方式存在如下問題:

1、硬編碼實現(xiàn)業(yè)務(wù)規(guī)則難以維護(hù)

2、硬編碼實現(xiàn)業(yè)務(wù)規(guī)則難以應(yīng)對變化

3、業(yè)務(wù)規(guī)則發(fā)生變化需要修改代碼,重啟服務(wù)后才能生效

那么面對上面的業(yè)務(wù)場景,還有什么好的實現(xiàn)方式嗎?

答案是規(guī)則引擎

2. 規(guī)則引擎概述

2.1 什么是規(guī)則引擎

規(guī)則引擎,全稱為業(yè)務(wù)規(guī)則管理系統(tǒng),英文名為BRMS(即Business Rule Management System)。規(guī)則引擎的主要思想是將應(yīng)用程序中的業(yè)務(wù)決策部分分離出來,并使用預(yù)定義的語義模塊編寫業(yè)務(wù)決策(業(yè)務(wù)規(guī)則),由用戶或開發(fā)者在需要時進(jìn)行配置、管理。

需要注意的是規(guī)則引擎并不是一個具體的技術(shù)框架,而是指的一類系統(tǒng),即業(yè)務(wù)規(guī)則管理系統(tǒng)。目前市面上具體的規(guī)則引擎產(chǎn)品有:drools、VisualRules、iLog等。

規(guī)則引擎實現(xiàn)了將業(yè)務(wù)決策從應(yīng)用程序代碼中分離出來,接收數(shù)據(jù)輸入,解釋業(yè)務(wù)規(guī)則,并根據(jù)業(yè)務(wù)規(guī)則做出業(yè)務(wù)決策。規(guī)則引擎其實就是一個輸入輸出平臺。

上面的申請信用卡業(yè)務(wù)場景使用規(guī)則引擎后效果如下:

系統(tǒng)中引入規(guī)則引擎后,業(yè)務(wù)規(guī)則不再以程序代碼的形式駐留在系統(tǒng)中,取而代之的是處理規(guī)則的規(guī)則引擎,業(yè)務(wù)規(guī)則存儲在規(guī)則庫中,完全獨(dú)立于程序。業(yè)務(wù)人員可以像管理數(shù)據(jù)一樣對業(yè)務(wù)規(guī)則進(jìn)行管理,比如查詢、添加、更新、統(tǒng)計、提交業(yè)務(wù)規(guī)則等。業(yè)務(wù)規(guī)則被加載到規(guī)則引擎中供應(yīng)用系統(tǒng)調(diào)用。

2.2 使用規(guī)則引擎的優(yōu)勢

使用規(guī)則引擎的優(yōu)勢如下:

1、業(yè)務(wù)規(guī)則與系統(tǒng)代碼分離,實現(xiàn)業(yè)務(wù)規(guī)則的集中管理

2、在不重啟服務(wù)的情況下可隨時對業(yè)務(wù)規(guī)則進(jìn)行擴(kuò)展和維護(hù)

3、可以動態(tài)修改業(yè)務(wù)規(guī)則,從而快速響應(yīng)需求變更

4、規(guī)則引擎是相對獨(dú)立的,只關(guān)心業(yè)務(wù)規(guī)則,使得業(yè)務(wù)分析人員也可以參與編輯、維護(hù)系統(tǒng)的業(yè)務(wù)規(guī)則

5、減少了硬編碼業(yè)務(wù)規(guī)則的成本和風(fēng)險

6、使用規(guī)則引擎提供的規(guī)則編輯工具,使復(fù)雜的業(yè)務(wù)規(guī)則實現(xiàn)變得的簡單

2.3 規(guī)則引擎應(yīng)用場景

對于一些存在比較復(fù)雜的業(yè)務(wù)規(guī)則并且業(yè)務(wù)規(guī)則會頻繁變動的系統(tǒng)比較適合使用規(guī)則引擎,如下:

1、風(fēng)險控制系統(tǒng)----風(fēng)險貸款、風(fēng)險評估

2、反欺詐項目----銀行貸款、征信驗證

3、決策平臺系統(tǒng)----財務(wù)計算

4、促銷平臺系統(tǒng)----滿減、打折、加價購

2.4 Drools介紹

drools是一款由JBoss組織提供的基于Java語言開發(fā)的開源規(guī)則引擎,可以將復(fù)雜且多變的業(yè)務(wù)規(guī)則從硬編碼中解放出來,以規(guī)則腳本的形式存放在文件或特定的存儲介質(zhì)中(例如存放在數(shù)據(jù)庫中),使得業(yè)務(wù)規(guī)則的變更不需要修改項目代碼、重啟服務(wù)器就可以在線上環(huán)境立即生效。

drools官網(wǎng)地址:https://drools.org/

drools源碼下載地址:https://github.com/kiegroup/drools

在項目中使用drools時,即可以單獨(dú)使用也可以整合spring使用。如果單獨(dú)使用只需要導(dǎo)入如下maven坐標(biāo)即可:

<dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>7.6.0.Final</version> </dependency>

如果我們使用IDEA開發(fā)drools應(yīng)用,IDEA中已經(jīng)集成了drools插件。如果使用eclipse開發(fā)drools應(yīng)用還需要單獨(dú)安裝drools插件。

drools API開發(fā)步驟如下:

3. Drools入門案例

本小節(jié)通過一個Drools入門案例來讓大家初步了解Drools的使用方式、對Drools有一個整體概念。

3.1 業(yè)務(wù)場景說明

業(yè)務(wù)場景:消費(fèi)者在圖書商城購買圖書,下單后需要在支付頁面顯示訂單優(yōu)惠后的價格。具體優(yōu)惠規(guī)則如下:

規(guī)則編號規(guī)則名稱描述
1規(guī)則一所購圖書總價在100元以下的沒有優(yōu)惠
2規(guī)則二所購圖書總價在100到200元的優(yōu)惠20元
3規(guī)則三所購圖書總價在200到300元的優(yōu)惠50元
4規(guī)則四所購圖書總價在300元以上的優(yōu)惠100元

現(xiàn)在需要根據(jù)上面的規(guī)則計算優(yōu)惠后的價格。

3.2 開發(fā)實現(xiàn)

第一步:創(chuàng)建maven工程drools_quickstart并導(dǎo)入drools相關(guān)maven坐標(biāo)

<dependency><groupId>org.drools</groupId><artifactId>drools-compiler</artifactId><version>7.10.0.Final</version> </dependency> <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version> </dependency>

第二步:根據(jù)drools要求創(chuàng)建resources/META-INF/kmodule.xml配置文件

<?xml version="1.0" encoding="UTF-8" ?> <kmodule xmlns="http://www.drools.org/xsd/kmodule"><!--name:指定kbase的名稱,可以任意,但是需要唯一packages:指定規(guī)則文件的目錄,需要根據(jù)實際情況填寫,否則無法加載到規(guī)則文件default:指定當(dāng)前kbase是否為默認(rèn)--><kbase name="myKbase1" packages="rules" default="true"><!--name:指定ksession名稱,可以任意,但是需要唯一default:指定當(dāng)前session是否為默認(rèn)--><ksession name="ksession-rule" default="true"/></kbase> </kmodule>

注意:上面配置文件的名稱和位置都是固定寫法,不能更改

第三步:創(chuàng)建實體類Order

package com.example.demo.entity;/*** 訂單* @author admin*/ public class Order {/*** 訂單原始價格,即優(yōu)惠前價格*/private Double originalPrice;/*** 訂單真實價格,即優(yōu)惠后價格*/private Double realPrice;@Overridepublic String toString() {return "Order{" +"originalPrice=" + originalPrice +", realPrice=" + realPrice +'}';}public Double getOriginalPrice() {return originalPrice;}public void setOriginalPrice(Double originalPrice) {this.originalPrice = originalPrice;}public Double getRealPrice() {return realPrice;}public void setRealPrice(Double realPrice) {this.realPrice = realPrice;} }

第四步:創(chuàng)建規(guī)則文件resources/rules/bookDiscount.drl (drl文件名稱可以隨意)

//圖書優(yōu)惠規(guī)則 package book.discount import com.example.demo.entity.Order//規(guī)則一:所購圖書總價在100元以下的沒有優(yōu)惠 rule "book_discount_1"when$order:Order(originalPrice < 100)then$order.setRealPrice($order.getOriginalPrice());System.out.println("成功匹配到規(guī)則一:所購圖書總價在100元以下的沒有優(yōu)惠"); end//規(guī)則二:所購圖書總價在100到200元的優(yōu)惠20元 rule "book_discount_2"when$order:Order(originalPrice < 200 && originalPrice >= 100)then$order.setRealPrice($order.getOriginalPrice() - 20);System.out.println("成功匹配到規(guī)則二:所購圖書總價在100到200元的優(yōu)惠20元"); end//規(guī)則三:所購圖書總價在200到300元的優(yōu)惠50元 rule "book_discount_3"when$order:Order(originalPrice <= 300 && originalPrice >= 200)then$order.setRealPrice($order.getOriginalPrice() - 50);System.out.println("成功匹配到規(guī)則三:所購圖書總價在200到300元的優(yōu)惠50元"); end//規(guī)則四:所購圖書總價在300元以上的優(yōu)惠100元 rule "book_discount_4"when$order:Order(originalPrice >= 300)then$order.setRealPrice($order.getOriginalPrice() - 100);System.out.println("成功匹配到規(guī)則四:所購圖書總價在300元以上的優(yōu)惠100元"); end

第五步:編寫單元測試

package com.example.demo.test;import com.example.demo.entity.Order; import org.kie.api.KieServices; import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession;public class Test {@org.junit.Testpublic void test1(){KieServices kieServices = KieServices.Factory.get();KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();//會話對象,用于和規(guī)則引擎交互(這里的參數(shù)取得是xml中配置的name,否則引擎不生效)KieSession kieSession = kieClasspathContainer.newKieSession("ksession-rule");//構(gòu)造訂單對象,設(shè)置原始價格,由規(guī)則引擎根據(jù)優(yōu)惠規(guī)則計算優(yōu)惠后的價格Order order = new Order();order.setOriginalPrice(210D);//將數(shù)據(jù)提供給規(guī)則引擎,規(guī)則引擎會根據(jù)提供的數(shù)據(jù)進(jìn)行規(guī)則匹配kieSession.insert(order);//激活規(guī)則引擎,如果規(guī)則匹配成功則執(zhí)行規(guī)則kieSession.fireAllRules();//關(guān)閉會話kieSession.dispose();System.out.println("優(yōu)惠前原始價格:" + order.getOriginalPrice() +",優(yōu)惠后價格:" + order.getRealPrice());}}

通過上面的入門案例我們可以發(fā)現(xiàn),使用drools規(guī)則引擎主要工作就是編寫規(guī)則文件,在規(guī)則文件中定義跟業(yè)務(wù)相關(guān)的業(yè)務(wù)規(guī)則,例如本案例定義的就是圖書優(yōu)惠規(guī)則。規(guī)則定義好后就需要調(diào)用drools提供的API將數(shù)據(jù)提供給規(guī)則引擎進(jìn)行規(guī)則模式匹配,規(guī)則引擎會執(zhí)行匹配成功的規(guī)則并將計算的結(jié)果返回給我們。

可能大家會有疑問,就是我們雖然沒有在代碼中編寫規(guī)則的判斷邏輯,但是我們還是在規(guī)則文件中編寫了業(yè)務(wù)規(guī)則,這跟在代碼中編寫規(guī)則有什么本質(zhì)的區(qū)別呢?

我們前面其實已經(jīng)提到,使用規(guī)則引擎時業(yè)務(wù)規(guī)則可以做到動態(tài)管理。業(yè)務(wù)人員可以像管理數(shù)據(jù)一樣對業(yè)務(wù)規(guī)則進(jìn)行管理,比如查詢、添加、更新、統(tǒng)計、提交業(yè)務(wù)規(guī)則等。這樣就可以做到在不重啟服務(wù)的情況下調(diào)整業(yè)務(wù)規(guī)則。

3.3 小結(jié)

3.3.1 規(guī)則引擎構(gòu)成

drools規(guī)則引擎由以下三部分構(gòu)成:

  • Working Memory(工作內(nèi)存)
  • Rule Base(規(guī)則庫)
  • Inference Engine(推理引擎)

其中Inference Engine(推理引擎)又包括:

  • Pattern Matcher(匹配器)
  • Agenda(議程)
  • Execution Engine(執(zhí)行引擎)

3.3.2 相關(guān)概念說明

Working Memory:工作內(nèi)存,drools規(guī)則引擎會從Working Memory中獲取數(shù)據(jù)并和規(guī)則文件中定義的規(guī)則進(jìn)行模式匹配,所以我們開發(fā)的應(yīng)用程序只需要將我們的數(shù)據(jù)插入到Working Memory中即可,例如本案例中我們調(diào)用kieSession.insert(order)就是將order對象插入到了工作內(nèi)存中。

Fact:事實,是指在drools 規(guī)則應(yīng)用當(dāng)中,將一個普通的JavaBean插入到Working Memory后的對象就是Fact對象,例如本案例中的Order對象就屬于Fact對象。Fact對象是我們的應(yīng)用和規(guī)則引擎進(jìn)行數(shù)據(jù)交互的橋梁或通道。

Rule Base:規(guī)則庫,我們在規(guī)則文件中定義的規(guī)則都會被加載到規(guī)則庫中。

Pattern Matcher:匹配器,將Rule Base中的所有規(guī)則與Working Memory中的Fact對象進(jìn)行模式匹配,匹配成功的規(guī)則將被激活并放入Agenda中。

Agenda:議程,用于存放通過匹配器進(jìn)行模式匹配后被激活的規(guī)則。

Execution Engine:執(zhí)行引擎,執(zhí)行Agenda中被激活的規(guī)則。

總結(jié)

以上是生活随笔為你收集整理的Drools规则引擎入门小demo的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。