摘要 這篇文章解釋了在J
EE應用中規則引擎及聲明性業務邏輯的優點
並且描述如何為流行的Spring框架開發簡單的規則引擎
此文需要讀者對Spring有基本的了解
任何大一點的軟件項目都包含了許多叫做業務邏輯的東西
業務邏輯的准確描述還是有爭議的
在為典型應用軟件的生成的大量代碼中
到處都是為如訂單處理
武器控制系統
圖形繪制等功能工作的零碎代碼
這些代碼與其他如處理持久化
日志
事務
語言偏好
框架特性及其他現代企業級應用有明顯不同
業務邏輯通常與其他代碼塊緊密的混和在一起
當重量級的侵入式框架(如EJB)被使用時
區別業務邏輯與框架生成的代碼就變得非常困難
有一個軟件需求在需求定義文檔很難准確描述
卻擁有使軟件項目成功或失敗的能力
適應性
這是用來衡量軟件響應業務變更容易程度的標准
現代企業要求響應快速及靈活
他們對企業軟件也有同樣的要求
可能你今天辛苦實現的業務規則在明天就被廢棄了而且要求你根據變更快速而准確的改變
當你的包含業務邏輯的代碼隱藏在大量其他代碼中時
修改就變得緩慢
痛若且易出錯了
在今天的企業級軟件中沒有奇跡
比較流行的是規則引擎和各種業務過程管理(BPM)系統
如果你看一下市場上的宣傳
這類工具都承諾一件事
保存在倉庫中的捕獲業務邏輯的聖杯能夠清晰的分離且由自己維護
並隨時准備讓你現有的應用來調用
雖然商業的規則引擎和BPM系統有許多優點
但也有不少缺點
最大的缺點就是價格
通常很容易就達到
位數
另一個就是除了主要的行業規范和眾多記在紙上的標准外缺乏事實上的標准
而且隨著越來越多的軟件項目采用敏捷
輕量級的快速開發方法
這些重量級的工具變得不符合潮流了
在這篇文章中
我們建立了一個簡單的規則引擎
一方面平衡系統與業務邏輯的分離
另一方面由於他基於目前流行的強大的J
EE框架因而不需要承受商業軟件的復雜性與不協調性
JEE世界中的Spring時代 在企業級軟件的復雜性變得不能忍受及業務邏輯問題越來越重要時
Spring及類似的框架產生了
可以斷定Spring在以後很長一段時間內是企業級Java中的佼佼者
Spring提供了很多工具及少量代碼約定使J
EE的開發更面向對象
更容易也更有趣
Spring的核心是IoC原則
這是一個奇特而超負荷的名字
但包含下面的簡單想法
●功能代碼需要分開到更小的可管理片斷
●這些片斷是簡單的
標准的JavaBean(簡單的Java類擁有但不包含全部的JavaBean規范)
●你不需要參與管理這些Bean(如創建
銷毀
設置依賴)
●相反Spring容器通過上下文定義來為你做這些(通常為XML文件格式)
Spring也提供了很多其他特性
如完整而強大的MVC框架
簡便的JDBC開發包裝及其他框架
但那些主題已經超出這篇幅文章的討論范圍
在我描述需要什麼來創建基於SPRING應用的簡單規則引擎之前
讓我們想一下為什麼這是一種好的想法
規則引擎設計有兩點有趣的特性使其更有價值
●首先
從應用領域分離了業務邏輯代碼
●其次
可配置性意味著業務規則的定義及其使用的順序被存儲在應用的外部
這樣就可以由規則創建人員來控制而不是應用的使用者或者開發人員了
Spring為規則引擎提供了一個好的方法
一個良好編碼的Spring應用的強組件化的設計會使你的代碼變成更小的
可管理的分散片斷
這樣就更易在Spring的上下文定義中配置
繼續了解在規則引擎設計的需求與Spring設計提供的功能之間的結合點
基於Spring的規則引擎的設計 我們在Spring控制的JavaBean基礎上開始設計
這裡我們叫做規則引擎組件
我們來定義下面兩種我們可能需要的組件類型
●操作—在應用邏輯中確定用來做什麼的組件
●規則—在一系列行為的邏輯流中做出決定的組件
我們都是面向對象設計的追隨者
下面的基類建立了所有我們的組件需要通過參數被其他組件調用的基本功能
public abstract class AbstractComponent { public abstract void execute(Object arg) throws Exception; }
當然基類是抽象的因為我們根本不需要這樣的實例
AbstractAction的代碼擴展了基類來實現其他具體的操作
public abstract class AbstractAction extends AbstractComponent { private AbstractComponent nextStep; public void execute(Object arg) throws Exception { this
doExecute(arg); if(nextStep != null) nextStep
execute(arg); } protected abstract void doExecute(Object arg) throws Exception; public void setNextStep(AbstractComponent nextStep) { this
nextStep = nextStep; } public AbstractComponent getNextStep() { return nextStep; }}
你可以看到
AbstractAction做兩件事
首先他保存在規則引擎中被激活的下一個組件的定義
其次在他的execute()方法中
調用被具體類實現的doExecute()方法
在doExecute()返回後
如果存在下一個組件則調用他
我們的AbstractRule也相當簡單
public abstract class AbstractRule extends AbstractComponent { private AbstractComponent positiveOutcomeStep; private AbstractComponent negativeOutcomeStep; public void execute(Object arg) throws Exception { boolean outcome = makeDecision(arg); if(outcome) positiveOutcomeStep
execute(arg); else negativeOutcomeStep
execute(arg); } protected abstract boolean makeDecision(Object arg) throws Exception;
// 為簡單起見
positiveOutcomeStep和negativeOutcomeStep 的Getters 和 setters均已省略
在其execute()方法中
AbstractAction調用由子類實現的makeDecision()方法
然後根據方法的返回值
調用組件定義的肯定或否定結果的方法
在我們介紹了SpringRuleEngine類後我們的設計就基本完成了
public class SpringRuleEngine { private AbstractComponent firstStep; public void setFirstStep(AbstractComponent firstStep) { this
firstStep = firstStep; } public void processRequest(Object arg) throws Exception { firstStep
execute(arg); } }
這就是我們規則引擎主類的全部
定義第一個業務邏輯中的組件及開始執行的方法
但是請稍等
在哪裡綁定我們的類使之可以工作呢?下面你就可以看到如何利用Spring來幫助我們完成工作的方法了
在操作中的基於Spring的規則引擎 讓我們看一下這個框架如何工作的具體實例吧
想象下面的用例
我們需要開發負責貸款申請的應用程序
我們需要滿足下面的條件
●檢查應用的完整性否則駁回
●檢查應用是否來自我們授權處理業務的應用
●檢查申請者的月收支比是否滿足我們的要求
●輸入的申請通過我們不知道實現細節的持久服務被存儲在數據庫中
我們只知道他的接口(可能這個開發被外包到印度了)
●業務規則是可以改變的
這也是為什麼需要規則引擎的設計了
首先
設計一個表示貸款申請的類
public class LoanApplication { public static final String INVALID_STATE =
Sorry we are not doing business in your state
; public static final String INVALID_INCOME_EXPENSE_RATIO =
Sorry we cannot provide the loan given this expense/income ratio
; public static final String APPROVED =
Your application has been approved
; public static final String INSUFFICIENT_DATA =
You did not provide enough information on your application
; public static final String INPROGRESS =
in progress
; public static final String[] STATUSES = new String[] { INSUFFICIENT_DATA
INVALID_INCOME_EXPENSE_RATIO
INVALID_STATE
APPROVED
INPROGRESS }; private String firstName; private String lastName; private double income; private double expences; private String stateCode; private String status; public void setStatus(String status) { if(!Arrays
asList(ntains(status)) throw new IllegalArgumentException(
invalid status:
+ status); this
status = status; }// 其他getters and setters已被省略}
我們使用的持久服務擁有如下接口
public interface LoanApplicationPersistenceInterface { public void recordApproval(LoanApplication application) throws Exception; public void recordRejection(LoanApplication application) throws Exception; public void recordIncomplete(LoanApplication application) throws Exception;}
我們迅速開發一個什麼也不做只是用來滿足接口約定的MockLoanApplicationPersistence類來欺騙接口
我們使用下面的SpringRuleEngine類的子類來加載Spring上下文並開始處理
public class LoanProcessRuleEngine extends SpringRuleEngine { public
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28349.html