當你開發一個客戶端應用程式的時候,往往一個單頁會包含很多子模組,在不同的平臺下,這些子模組又被叫成子View(檢視),或者子Component(元件)。越是複雜的頁面,被切割出來的子模組就越多,子模組越多,彼此之間需要同步的資料和狀態就越頻繁,即易產生耦合。那麼如何保證在複雜業務情況下,各個子模組之間可以隨意通訊並保持弱耦合關係,這正是本文所討論的。
耦合的產生
試想一下,你有這樣一下需求,點選 View A中的按鈕,View B也需要做出相應的改變。
這不是很簡單嗎。腦海裡迅速出現兩種解決方案:
1.View A 主動通知View B做出更新,也就是View A依賴 View B
void Notify()
{
ViewB.Update(color);
}複製程式碼
2.View B監聽View A的ColorChanged事件,主動拉取資料並更新,即ViewB 依賴View A
ViewA.OnColorPropertyValueChanged+=(color)=>{
Update(color);
}複製程式碼
這兩種實現毫無疑問是沒問題的,至少從結果上來看是正確的。但試想一下,在一個複雜的客戶端單頁應用程式,這種緊耦合關係會導致程式的複雜度陡然上升。每個View/ViewModel依賴其餘物件,而本身又被其他View/ViewModel強引用。這顯然不是好的實踐方式。
還記得我在上一篇文章的對於MVVM的描述嗎?
MVVM的核心思想就是解耦,View與ViewModel應該感受不到彼此的存在。ViewModel與ViewModel之間也應該感受不到彼此的存在。
中介者模式的引入
那麼如何消除這種緊耦合關係呢?交給中介者設計模式來解決吧。
我們需要新增一箇中介者,每個ViewModel Publisher物件都會在自己狀態改變時,告訴中介者。每個ViewModel Subscribers 都需要告訴中介者請求來時進行怎樣的響應。
在沒有中介者之前物件之間都需要彼此認識,互相引用,是一種強耦合關係。有了中介者之後,徹底解耦。
那麼現在就需要定義一箇中介者,稱為MessageAggregator。因為由它來轉發訊息,所以核心是一個字典,儲存了所有需要被轉發的訊息。它的Key為訊息的唯一Id,Value代表一個對該Message的處理程式。
public delegate void MessageHandler<T>(object sender, MessageArgs<T> args);
public class MessageAggregator<T>
{
private readonly Dictionary<string, MessageHandler<T>> _messages = new Dictionary<string, MessageHandler<T>>();
public static readonly MessageAggregator<T> Instance=new MessageAggregator<T>();
private MessageAggregator()
{
}
public void Subscribe(string name, MessageHandler<T> handler)
{
if (!_messages.ContainsKey(name))
{
_messages.Add(name, handler);
}
else
{
_messages[name] += handler;
}
}
public void Publish(string name, object sender, MessageArgs<T> args)
{
if (_messages.ContainsKey(name) && _messages[name] != null)
{
//轉發
_messages[name](sender, args);
}
}
}複製程式碼
解耦ViewModel與ViewModel
通過中介者MessageAggregator物件,ViewModelB Subscribe一個對訊息來時的處理函式:
MessageAggregator<object>.Instance.Subscribe("ColorChanged",ToggleHandler);複製程式碼
ViewModel A在自己狀態改變時,Pulish狀態改變的訊息給中介者:
MessageAggregator<object>.Instance.Publish("ColorChanged", this,new MessageArgs<object>("Red"));複製程式碼
小結
中介者模式常常用來協調相關的GUI元件,可以讓物件之間傳遞的訊息變得簡單。但如果設計不當,中介者本身會變得過於複雜。
原始碼託管在Github上,點選此瞭解
歡迎關注我的公眾號: