最近在處理自定義表單時,需要自定義業(yè)務規(guī)則,最終在網上看到jxb8901先生的文章,和我的部分想法類似,特別是對于表達式的要求上,非常贊賞。區(qū)別在于我需要的表達式是基于組件的。原文如下:
一、問題
系統(tǒng)要求實現類似如下規(guī)則:
代碼
積分規(guī)則:憑XX信用卡消費1元人民幣,即可獲得1分的消費積分, 在汽車類商戶每消費100元人民幣積8分,在房地產類商戶每消費100元人民幣積6分。 兌獎規(guī)則:100分~300分:兌換150元禮品,300分~500分兌換300元禮品, 500分以上兌換400元禮品
因為系統(tǒng)中有大量類似這樣的規(guī)則,而且規(guī)則會經常變動,另外業(yè)務上也要求這樣的規(guī)則最好能由業(yè)務人員自己定義和修改,因此一個很自然的考慮是使用規(guī)則引擎來實現。
二、現有規(guī)則引擎產品分析
最初希望使用商業(yè)或開源的規(guī)則引擎,但從網上搜索的關于規(guī)則引擎的資料來看,現有規(guī)則引擎實現這樣的應用好象不太合適。
1、如何定義規(guī)則?
一般規(guī)則引擎中定義規(guī)則的方式如下:
代碼
if{ 規(guī)則 } then{ 動作 }
但這樣的規(guī)則“消費1元人民幣積1分”使用if...then...該如何定義呢?好象沒法定義。
另外感覺這類規(guī)則定義就是一系列的if...then...這其中的邏輯和我們在java中的邏輯沒有什么區(qū)別,
只是換了一種形式而已。這樣的規(guī)則根本沒辦法給業(yè)務人員使用。
2、如何處理數據庫與規(guī)則引擎的關系?
再者規(guī)則引擎是基于事實進行推演,所以在觸發(fā)規(guī)則引擎計算之前,需要先裝入事實?;贘SR94的實現
多使用OO的方式,例如:
代碼
loadRules();//裝入規(guī)則 WorkingMemoryworkingMemory=businessRules.newWorkingMemory(); workingMemory.addEventListener(newDebugWorkingMemoryEventListener()); workingMemory.assertObject(student);//裝入事實 workingMemory.fireAllRules(filter);//觸發(fā)計算
摘自http://www.blogchinese.com/06042/201878/archives/2006/200652418217.shtml
這里就有一個問題,如果我的事實是基于數據庫記錄,那么該如何裝入事實?因為規(guī)則的定義中條件部分
一般是基于對象的屬性,動作部分一般是基于對象的方法,所以如果事實能使用數據記錄,那么條件特別是
動作該如何定義?
3、需要Rete算法嗎?
只要對規(guī)則引擎稍有接觸,應該都聽說過“Rete算法”,現有的商業(yè)或開源的規(guī)則引擎多是基于該算法。多數會解決
這樣一個問題,就是自動處理動作對事實的反饋,如果一個動作影響了事實,那么會重新針對事實過濾規(guī)則,我想這樣的反饋
計算可能大大影響了規(guī)則引擎的性能,而正Rete算法解決了規(guī)則引擎的性能問題。但上述規(guī)則并不需要這樣的特性,所以性能問題不會表現在這些方面。
因為對這類商業(yè)和開源的規(guī)則只是有一個泛泛的了解,不知其能否解決這些問題?怎樣解決這些問題?
三、方案
終合上述考慮,決定自己實現規(guī)則引擎,首要的就是將上述語句表示為規(guī)則引擎能識別的規(guī)則,自然需要一套語法來定義這樣的規(guī)則,
結合實現及面向業(yè)務人員這樣的需求,大略將上述語句轉換為如下規(guī)則定義:
代碼
客戶積分+=POS消費總額(商戶類型!=汽車類|房地產類){主體=XX信用卡客戶} 客戶積分+=POS消費總額(商戶類型=汽車類)/100*6{主體=XX信用卡客戶} 客戶積分+=POS消費總額(商戶類型=房地產類)/100*8{主體=XX信用卡客戶} 客戶積分-=如果(兌換獎品總額>=400,500){主體=XX信用卡客戶,扣減規(guī)則=(消費類型=退貨)} 客戶積分-=如果(兌換獎品總額>=300,300){主體=XX信用卡客戶,扣減規(guī)則=(消費類型=退貨)} 客戶積分-=如果(兌換獎品總額>=150,100){主體=XX信用卡客戶,扣減規(guī)則=(消費類型=退貨)}
個人感覺如果能這樣定義規(guī)則的話業(yè)務人員應該很容易就能看懂,也能很容易修改。
針對上述實現,我提出以下要求:
代碼
語法簡單,業(yè)務人員很容易明白 必須支持中文規(guī)則定義 必須支持自定函數(我想象的"POS消費總額","如果"都是函數) 很容易擴展函數 最好=,>,<之類的符號可以支持全角字符
四、實現
現在考慮如果要用程序實現上述規(guī)則,有以下兩種方案:
1、使用動態(tài)腳本語言實現規(guī)則解析,如ruby,groovy,jaskell之類的(好象這就叫DSL吧),但

不知能不能滿足我上面提出的要求。
2、使用javacc,antlr定義語法生成解析器。
第二種方案的好處是靈活性足夠強,而且能滿足“中文定義”的要求,但要權衡,維護和調試一個解析器也不是一件輕松的事。
原文出處:http://www.javaeye.com/article/25215?page=3
愛華網



