程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 【插件式框架探索系列】建立基於委托的訂閱發布機制

【插件式框架探索系列】建立基於委托的訂閱發布機制

編輯:關於.NET

前些時候有個想法,想把自己感覺很有意思且方便平時開發的東西合起來,建立一個Framework,它會讓開發變得更得心應手,可惜後來隨著更多的東西被加入其中,越來越發覺這可能並不是一個開發者需要的東西,因為它太雜了,是的,作為一個Framework,還是單純點的好,後來工作也忙了,就停滯了。這幾天出差廣州,夜來無事,便撿個模塊來說道說道。

Messenger

在平時的開發中,數據的傳遞、處理等可以通過事件機制來完成,但是事件機制會引入耦合,當然這種耦合很多時候是合理的,但是卻有那麼一些時候這種耦合卻不是你所需要的,過多的依賴會讓你感到困惑,而引入Messenger就是為了解除這種依賴,請看下圖。

Figure 1. 類之間的單向依賴

Figure 2. 類之間的雙向依賴

Figure 3. 引入Messenger後的依賴關系

Messenger的概念來自MVVM Foundation項目,在看完該項目的源代碼後,發現其中的Messenger是個很好的機制,就借鑒這個機制結合實際情況設計了自己的Messenger。

顧名思義,Messenger在這裡作為行為的傳遞者,其職責是預先接受行為的訂閱,在需要的時候執行這些行為,即發布。

Figure 4. Messenger類圖

從類圖上我們看到Messenger提供了訂閱、取消訂閱和發布行為的能力。Messenger內置一個數據結構用於存儲訂閱的行為,存儲結構描述為Dictionary<T, List<WeakAction>>,T為行為在語義上的含義,作為字典的Key,其對應一組行為,而每個行為都以 WeakAction表示,WeakAction會保證Messenger與定義行為的對象之間保持弱引用(WeakRefernce)關系,避免內存洩漏,如此便構成了行為的存儲結構MessageToActionMap。

Figure 5. MessageToActionMap類圖

Figure 6. WeakAction類圖

終於Messenger擁有了訂閱和發布行為的能力,為了提供更好的靈活性,Messenger被定義為泛型抽象類型,具體的Messenger通過繼承方式擴展,在此,我們定義了幾種典型的Messenger實現:

Firgure 7. Messenger實現

Ø GeneralMessenger

GeneralMessenger作為Messenger的一個通用實現,繼承自Messenger<object>,適用於大多數場景。

Ø TypeMessenger

TypeMessenger更適用於基於消息驅動的應用場景,在分布式應用中,系統間會互相傳遞消息,而消息的接收方往往會依據不同的消息類型作出不同的處理,比如Server收到Client的登錄請求時會去執行驗證行為,而收到登出請求時會作出釋放資源行為。當然所有的這些,GeneralMessenger完全可以勝任,只不過TypeMessenger更加方便,後面提到的數據的訂閱發布機制便是使用 TypeMessenger實現的。

Ø OnceOffMessenger

OnceOffMessenger作為GeneralMessenger的特殊實現,它最特殊的地方便是訂閱的行為,在發布後即消亡,適用於處理一次性的行為。

為了適應各種不同的開發場景,Messenger本身是可以創建多個實例的,如果想實現單例模式,可以通過使用SingletonManager.GetInstance<T>方法獲取單例。

Firgure 8. SingletonManager類圖

1 TypeMessenger messenger = SingletonManager.GetInstance<TypeMessenger>();

數據的訂閱發布機制

發布者的職責是提供數據,而訂閱者的職責則是消費數據,即處理數據,當然訂閱者可以同時也是發布者,如此可以實現數據的再處理。為此定義了發布接口和訂閱接口:

Firgure 9. 訂閱發布接口類圖

同時提供訂閱和發布的標准實現:

Firgure 10. 訂閱發布標准實現類圖

我們可以看到訂閱者同時也是發布者,兩者皆是使用TypeMessenger實現訂閱發布機制。

SubscriberAdapter<T>的Subscribe方法中訂閱T的處理行為為Handle方法:

1 /// <summary>
2 /// Subscribe the message handler.
3 /// </summary>
4 public void Subscribe()
5 {
6     messenger.Subscribe<T>(new Action<T>(msg => Handle(msg)));
7 }

而在PublisherAdapter的OnMessage和OnMessageAsyn方法中發布數據:

01 /// <summary>
02 /// Publish the message.
03 /// </summary>
04 /// <param name="message">The message.</param>
05 public virtual void OnMessage(object message)
06 {
07     if (message != null)
08     {
09         messenger.NotifyAll(message);
10     }
11 }
12
13 /// <summary>
14 /// Publish the message asynchronously.
15 /// </summary>
16 /// <param name="message">The message.</param>
17 public virtual void OnMessageAsyn(object message)
18 {
19     if (message != null)
20     {
21         messenger.NotifyAllAsyn(message);
22     }
23 }

同時在SubscriberAdapter<T>中也可以以類似的方式發布數據,該數據類型的訂閱者會處理該數據。

這種設計方式也是借鑒於Apache MINA框架中的過濾器概念,讓數據在一個過濾器鏈中傳遞,鏈上的每個過濾器都有機會對數據進行處理和再加工。不過這裡的訂閱者的數據發布行為只能發布不同於當前類型的數據,否則會進入無限制的死循環,該行為已經通過重載PublisherAdapter的OnMessage和OnMessageAsyn方法實現。

寫在後面

事件機制傳遞數據很方便,也比較簡單,只是個人覺得還是這種方式更加靈活,也更加簡單。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved