天天看點

堅持學習WF(21):規則引擎中的RuleSet

<a href="http://www.cnblogs.com/carysun/archive/2008/05/29/WF.html">堅持學習WF文章索引</a>

這次繼續學習WF中規則引擎中的相關知識。WF中的每一個規則都包括下面三部分:

1. 一個條件傳回true或false 

2. 一個then操作(當條件為true時執行) 

3. 一個else操作(當條件為false時執行)

規則對應System.Workflow.Activities.Rules命名空間中中的Rule類,Rule類的ThenActions,ElseActions都是RuleAction對象的集合。RuleAction是一個抽象類,他的派生類RuleStatementAction指定要更新的屬性或字段或要使用 CodeDom 類型運作的方法。還有RuleHaltActin和RuleUpdateAction派生類。RuleStatementAction可以使用簡單的fieldA=10,或複雜的計算fieldA=fieldC*3.14,RuleStatementAction的語句塊将被序列化為CodeDom對象,CodeDom對象來辨別内部的源代碼的架構,能動态的生成和編譯。如果你使用規則編輯器,你可以不用了解他的細節,但是你要自己動态的在代碼中聲明規則,你就要好好了解下了。RuleHaltAction類導緻 RuleSet停止執行并使控制重新傳回到調用方法。RuleUpdateAction 類此類用于向規則引擎訓示執行此規則的操作集可導緻指定的字段或屬性(或一個對象的所有字段和屬性)發生更改,進而可以重新計算依賴于此字段或屬性的任何規則。Update 調用不會阻止操作塊中其他操作的執行。修改的字段/屬性集(通過 Update 指定或通過對調用的方法使用 RuleWriteAttribute來指定)用于确定此特定規則的操作集完成執行時的連結。

我們可以将規則視為 IF-THEN-ELSE 語句,其中,條件對應于IF,而操作定義 THEN 和 ELSE 子句的行為。這樣的一組規則便組成了規則集RuleSet,規則集既支援規則的簡單依序執行,也支援規則的複雜正向連結。 規則集可以由PolicyActivity 活動執行。使用PolicyActivity活動時我們隻需要将該活動拖到工作流設計器中, 然後配置 PolicyActivity 上的 RuleSetReference 屬性,按名稱指向 RuleSetCollection 中的 RuleSet。 PolicyActivity 活動建立 RuleSet 類的執行個體;規則是由 RuleSet 類執行的。下圖為VS2008中的規則集編輯器:

<a href="http://www.cnblogs.com/images/cnblogs_com/carysun/WindowsLiveWriter/WF21RuleSet_12295/rule11.jpg"></a>

我們可以看到每個規則都有一個(priority)優先級的屬性,優先級大的會先執行。雖然設定優先級可以改變規則集中規則的執行順序,但一般都不會去設定該屬性,因為WF的規則引擎有重新計算的能力:(forward chaining)正向連結。下面我就來說說規則引擎中非常重要的正向連結特性。

正向連結 

RuleSet類的ChainingBehavior屬性表示擷取或設定 RuleSet中 Rule 類的正向連結行為。決定規則引擎是如何執行正向連結的,這個屬性的值是枚舉類型RuleChainingBehavior。下面是各個取值的說明:

None(順序的):訓示不執行連結。每個規則隻執行一次。 

UpdateOnly(僅顯示更新):訓示如果已執行的操作使用 RuleUpdateAction 明确指定連結,則執行該連結。 

Full(完全連結):訓示由操作修改字段或屬性、為由操作調用的方法指定 RuleWriteAttribute或執行 RuleUpdateAction時執行該連結。

下面舉個例子:

Rule

Conditon

ThenAction

ElseAction

Rule1

A&gt;10

B=60

B=40

Rule2

B&gt;50

C="preferred"

C="normal"

Rule3

D&lt;100

B=B*0.80

我們可以看出A和D是輸入變量,B和C是規則中設定的。如果我們使用完全正向連結的選項,規則引擎會自動根據這些規則來覺得是否需要重新計算之前的規則,比如A是12,D是99的話,

1. Rule1 A&gt;10 是以B=60 

2. 到了Rule2 B=60,大于50,是以C="preferred" 

3. Rule3 D=99 &lt;100 是以B=60*0.80=48 

4. 這個時候B=48,B的值改變了,是以Rule2會重新計算,B&lt;50 C="normal" 

5. Rule3不會重新計算,因為他包含的變量自從第一次計算後沒有變化。

最後的結果是B=48,C="normal",A D沒有變化。如果你将正向連結的屬性設為None屬性的,每個規則将執行一次,最後的結果将是B=48,C="preferred"。

使用Update語句 

有的時候我們不需要完全的正向連結,我們使用UpdateOnly,UpdateOnly 選項關閉隐式的、基于屬性的連結,并規定連結隻應對顯式 Update 語句發生。 這使您能夠完全控制哪些規則引起重新計算。  這個時候我們必須使用Update語句,通過這個語句可以告訴WF,某個屬性一定會被修改了,相關的規則可能需要重新應用。

下面舉例說明,

B=60 ,Update(B)

B=40 ,Update(B)

C="preferred",Update(C)

C="normal",Update(C)

B=B*0.80,Update(B)

Update語句在序列化到.rules檔案的時候會生成RuleUpdateAction,每個Update語句表示是否被其他條件更改,使用此選項可以避免導緻規則過度(甚至是失控)重複執行的循環依賴性,或者通過消除為提供 RuleSet 的功能完整性所不需要的規則重新計算來提高性能。

禁止規則重算 

另一個影響規則計算的是Rule類的ReevaluationBehavior屬性,擷取或設定一個值,該值訓示是否可以重新計算 Rule。其值為RuleReevaluationBehavior,預設是Always,還有Never.對應于上面圖中的重新計算選項。

Always :為預設值,它提供了前面讨論過的行為,即,總是根據其他規則的操作所引起的連結重新計算規則。 

Never: 顧名思義就是關閉重新計算。 規則計算一次,但如果該規則先前已執行了任何操作,則不進行重新計算。 換言之,如果先前計算過該規則,并是以執行了其 Then 或 Else 操作,則不會重新計算該規則。 但是,執行 Then 或 Else 操作中的空操作集合并不表示規則已經執行。

基于屬性 

當一個規則的條件或執行為字段或屬性的時候,WF的規則引擎可以識别他們的關系來控制正向連結,如果是方法的時候就不行了,比如GetAccountStatus方法,我們可以猜到這個方法是擷取Account的狀态值,但是WF确猜不到,我們使用下面的一組屬性來解決這個問題。

一共三個RuleReadAttribute,RuleWriteAttribute 和RuleInvokeAttribute 類分别表示用于讀取條件、寫入操作和調用方法的屬性。通過屬性來标明哪些是對條件表達式的修改。下面是例子:

this.discount &gt; 0

this.total = (1-this.discount) * this.subtotal

this.subtotal &gt; 10000

this.SetDiscount(0.05)

然後,可以将 SetDiscount 方法按如下方式進行屬性設定。 這會使引擎能夠辨別規則 1 依賴于規則 2,因為使用了折扣字段。

this.SetDiscountWrapper(0.05)

[RuleInvoke("SetDiscount")] 

void SetDiscountWrapper(double requestedDiscount) 

{    

     SetDiscount(requestedDiscount);  

[RuleWrite("discount")] 

void SetDiscount(double requestedDiscount) 

}

可以使用屬性指定如何在方法中使用參數。 例如,通過對以下方法進行屬性 (attribute) 設定,訓示此方法修改傳遞的 Order 執行個體上的 Discount 屬性 (property)。

在規則屬性中還可以使用通配符。 例如,可以使用 RuleWrite("order/*") 訓示此方法修改“order”字段引用的對象上的所有字段。 但是,隻能在路徑的末尾使用通配符;像 RuleWrite("*/Discount") 之類的屬性無效。

像 RuleWrite("order") 之類的屬性可以與引用類型一起使用以訓示引用已更改,例如,訓示變量目前指向其他 Order 執行個體。 除了測試執行個體引用本身的所有規則外,使用字段/屬性的所有規則也都假定為受到影響;例如 IF this.order == this.order2。

在未指定方法屬性情況下的預設行為,是假定方法調用在目标對象(即對其調用方法的對象)上不讀取或寫入任何字段/屬性。 此外,假定該方法調用根據 .NET Framework 中定義的關鍵字(ref、out、ByVal、ByRef 等)讀取參數和寫入參數。

本文轉自生魚片部落格園部落格,原文連結:http://www.cnblogs.com/carysun/archive/2008/09/21/RuleSet.html,如需轉載請自行聯系原作者

繼續閱讀