Attribute在.NET程式設計中的應用(五) (轉)

worldblog發表於2008-01-31
Attribute在.NET程式設計中的應用(五) (轉)[@more@]

Attribute在中的應用(五)

Attribute在攔截機制上的應用

從這一節開始我們討論Attribute的高階應用,為此我準備了一個實際的例子:我們有一個訂單處理,當一份訂單提交的時候,系統檢查庫存,如果庫存存量滿足訂單的數量,系統記錄訂單處理記錄,然後庫存,如果庫存存量低於訂單的數量,系統做相應的記錄,同時向庫存管理員傳送。為了方便演示,我們對例子進行了簡化:

//Inventory.cs using System; using System.Collections; namespace NiwalkerDemo { public class Inventory { private Hashtable inventory=new Hashtable(); public Inventory() { inventory["Item1"]=100; inventory["Item2"]=200; } public bool Checkout(string product, int quantity) { int qty=GetQuantity(product); return qty>=quantity; } public int GetQuantity(string product) { int qty=0; if(inventory[product]!=null) qty = (int)inventory[product]; return qty; } public void Update(string product, int quantity) { int qty=GetQuantity(product); inventory[product]=qty-quantity; } } } //Logbook.cs using System; namespace NiwalkerDemo { public class Logbook { public static void Log(string logData) { Console.WriteLine("log:{0}",logData); } } } //Order.cs using System; namespace NiwalkerDemo { public class Order { private int orderId; private string product; private int quantity; public Order(int orderId) { this.orderId=orderId; } public void Submit() { Inventory inventory=new Inventory(); //建立庫存 //檢查庫存 if(inventory.Checkout(product,quantity)) { Logbook.Log("Order"+orderId+" available"); inventory.Update(product,quantity); } else { Logbook.Log("Order"+orderId+" unavailable"); SendE(); } } public string ProductName { get{ return product; } set{ product=value; } } public int OrderId { get{ return orderId; } } public int Quantity { get{ return quantity;} set{ quantity=value; } } public void Send() { Console.WriteLine("Send email to manager"); } } }


下面是:

//AppMain.cs using System; namespace NiwalkerDemo { public class AppMain { static void Main() { Order order1=new Order(100); order1.ProductName="Item1"; order1.Quantity=150; order1.Submit(); Order order2=new Order(101); order2.ProductName="Item2"; order2.Quantity=150; order2.Submit(); } } }


程式看上去還不錯,商務物件封裝了商務規則,執行的結果也符合要求。但是我好像聽到你在抱怨了,沒有嗎?當你的客戶的需求改變的時候(客戶總是經常改變他們的需求),比如庫存檢查的規則不是單一的檢查產品的數量,還要檢查產品是否被預訂的多種情況,那麼你需要改變Inventory的程式碼,同時還要修改Order中的程式碼,我們的例子只是一個簡單的商務邏輯,實際的情況比這個要複雜的多。問題在於Order物件同其他的物件之間是緊耦合的,從的觀點出發,這樣的設計是有問題的,如果你寫出這樣的程式,至少不會在我的團隊裡面被Pass.

你說了:“No problem! 我們可以把商務邏輯抽出來放到一個專門設計的用來處理事務的物件中。”嗯,好主意,如果你是這麼想的,或許我還可以給你一個提議,使用Observer Design Pattern(觀察者設計):你可以使用delegate,在Order物件中定義一個BeforeSubmit和AfterSubmit事件,然後建立一個物件連結串列,將相關的物件插入到這個連結串列中,這樣就可以實現對Order提交事件的攔截,在Order提交之前和提交之後自動進行必要的事務處理。如果你感興趣的話,你可以自己動手來編寫這樣的一個程式碼,或許還要考慮在分散式環境中(Order和Inventory不在一個地方)如何處理物件之間的互動問題。

幸運的是,.NET 中提供了實現這種技術的支援。在.NET Framework中的物件Remoting和服務中,有一個重要的攔截機制,在物件Remoting中,不同的應用程式之間的物件的互動需要穿越他們的域邊界,每一個應用域也可以細分為多個Context(上下文環境),每一個應用域也至少有一個預設的Context,即使在同一個應用域,也存在穿越不同Context的問題。NET的元件服務發展了COM+的元件服務,它使用Context Attribute來實現象COM+一樣的攔截功能。透過對呼叫物件的攔截,我們可以對一個方法的呼叫進行前處理和後處理,同時也解決了上述的跨越邊界的問題。

需要提醒你,如果你在MSDN文件查ContextAttribute,我可以保證你得不到任何有助於瞭解ContextAttribute的資料,你看到的將是這麼一句話:“This type supports the Framework infrastructure and is not intended to be used directly from your code.”——“本型別支援.NET Framework基礎結構,它不打算直接用於你的程式碼。”不過,在msdn站點,你可以看到一些有關這方面的資料(見文章後面的參考連結)。

下面我們介紹有關的幾個類和一些概念,首先是:

ContextAttribute類

ContextAttribute派生自Attribute,同時它還實現了IContextAttribute和IContextProperty介面。所有自定義的ContextAttribute必須從這個類派生。
構造器:
ContextAttribute:構造器帶有一個引數,用來設定ContextAttribute的名稱。

公共屬性:
Name:只讀屬性。返回ContextAttribute的名稱

公共方法:
GetPropertieorNewContext:虛擬方法。向新的Context新增屬性集合。
IntextOK:虛擬方法。查詢客戶Context中是否存在指定的屬性。
IsNewContextOK:虛擬方法。預設返回true。一個物件可能存在多個Context,使用這個方法來檢查新的Context中屬性是否存在衝突。
Freeze:虛擬方法。該方法用來定位被建立的Context的最後位置。

ContextBound類

實現被攔截的類,需要從ContextBoundObject類派生,這個類的物件透過Attribute來指定它所在Context,凡是進入該Context的呼叫都可以被攔截。該類從MarshalByRefObject派生。

以下是涉及到的介面:

IMessage:定義了被傳送的訊息的實現。一個訊息必須實現這個介面。

IMessageSink:定義了訊息接收器的介面,一個訊息接收器必須實現這個介面。

還有幾個介面,我們將在下一節結合攔截構架的實現原理中進行介紹。
(待續)


參考文章:.com/msdnmag/issues/03/03/contextsinnet/">Decouple Components by Injecting Custom Services into Your Object's Interception Chain


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-998921/,如需轉載,請註明出處,否則將追究法律責任。

相關文章