Unity應用架構設計(2)——使用中介者模式解耦ViewModel之間通訊

木宛城主發表於2017-07-06

當你開發一個客戶端應用程式的時候,往往一個單頁會包含很多子模組,在不同的平臺下,這些子模組又被叫成子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上,點選此瞭解

歡迎關注我的公眾號:

相關文章