意圖(Intent)#
定義一個物件來封裝一組物件之間的互動方式。Mediator 透過避免物件之間直接相互參照來促進鬆耦合,並允許獨立地改變它們之間的互動。
動機(Motivation)#
物件導向設計鼓勵將行為分散到多個物件中,但這可能導致物件之間產生大量的互連——最壞的情況是每個物件都認識其他所有物件,系統變得如同一個整體。大量的相互依賴使得物件難以獨立複用,也難以修改系統行為。
以 GUI 中的對話框(dialog box) 為例:
- 對話框包含多個 widget(按鈕、輸入欄位、列表框等)
- widget 之間存在各種依賴:輸入欄位為空時按鈕被停用;選取列表項目會更新輸入欄位;輸入文字可能反向選取列表項目
- 不同對話框有不同的依賴關係,無法簡單複用
Mediator 的解法是將所有集體行為封裝在一個獨立的 mediator 物件中。例如 FontDialogDirector 作為字型對話框中 widget 之間的中介者:
- 列表框(ListBox)告知 director 自己的選擇改變了
- Director 從列表框取得選中項目
- Director 將選中項目傳給輸入欄位(EntryField)
- Director 啟用對應的按鈕
Widget 之間只透過 director 間接通訊,彼此不需要認識。
Mediator 的核心思想是用一對多的關係取代多對多的關係。所有物件只認識 mediator,透過 mediator 間接協作,大幅降低物件之間的耦合。
適用場景(Applicability)#
- 一組物件以定義明確但複雜的方式通訊,產生的相互依賴難以理解
- 物件難以複用,因為它參照並通訊的其他物件太多
- 分散於多個類別的行為需要可客製化,但不想產生大量子類別
結構(Structure)#
Mediator 定義與 Colleague 物件通訊的介面。ConcreteMediator 透過協調 Colleague 物件來實作合作行為,並維護對其 colleague 的參照。每個 Colleague 只認識自己的 Mediator,在需要與其他 colleague 通訊時改為通知 mediator。
classDiagram
class Mediator {
<<interface>>
}
class ConcreteMediator
class Colleague {
<<interface>>
}
class ConcreteColleague1
class ConcreteColleague2
Mediator <|.. ConcreteMediator
Colleague <|.. ConcreteColleague1
Colleague <|.. ConcreteColleague2
Colleague --> Mediator
ConcreteMediator --> ConcreteColleague1
ConcreteMediator --> ConcreteColleague2參與者(Participants)#
| 參與者 | 範例 | 職責 |
|---|---|---|
| Mediator | DialogDirector | 定義與 Colleague 物件通訊的介面 |
| ConcreteMediator | FontDialogDirector | 透過協調 Colleague 物件來實作合作行為;認識並維護其所有 colleague |
| Colleague 類別 | ListBox、EntryField | 每個 Colleague 認識自己的 Mediator;需要與其他 colleague 通訊時,改為與 mediator 通訊 |
協作方式(Collaborations)#
- Colleague 向 Mediator 發送與接收請求
- Mediator 透過在適當的 colleague 之間路由請求來實作合作行為
優缺點(Consequences)#
優點:
- 限制子類別化——修改行為只需子類別化 Mediator,Colleague 類別可原樣複用
- 解耦 colleague——可獨立地變更和複用 Colleague 與 Mediator 類別
- 簡化物件協定——將多對多互動替換為一對多,更易理解、維護和擴展
- 抽象化協作方式——將中介邏輯獨立封裝,有助於釐清系統中物件如何互動
缺點:
- 中心化控制的代價——Mediator 將互動的複雜度集中到自身,可能變成一個難以維護的龐大類別
Mediator 將分散的複雜度集中為自身的複雜度。當 colleague 數量增加或互動邏輯複雜化時,mediator 可能膨脹為難以維護的「上帝物件(god object)」。需要留意適時拆分。
實作要點(Implementation)#
- 省略抽象 Mediator 類別——若 colleague 只與單一 mediator 協作,不需要定義抽象 Mediator 類別。抽象類別的價值在於讓 colleague 能與不同的 Mediator 子類別協作
- Colleague-Mediator 通訊方式
- Observer 模式:Colleague 作為 Subject,mediator 作為 Observer,colleague 狀態改變時發送通知
- 專用通知介面:在 Mediator 中定義特化的通知方法,colleague 通訊時將自己作為參數傳入,讓 mediator 能辨識發送者
使用 Observer 模式作為 colleague-mediator 的通訊機制可以增加彈性——colleague 不需要知道具體的 mediator 類別,只需發送通知。但若需要更直接的通訊,專用介面更為清晰高效。
已知應用(Known Uses)#
- ET++ 和 THINK C 類別庫 在對話框中使用 director-like 物件作為 widget 之間的 mediator
- Smalltalk/V for Windows 的應用程式架構基於 mediator 結構:
ViewManager是 Mediator,各Pane(TextPane、ListBox、Button 等)只認識自己的 view manager,透過事件機制通訊 - Observer 模式中的 ChangeManager 在 subject 與 observer 之間中介,避免冗餘更新
- Unidraw 的
CSolver在圖形編輯器中的 connector 之間中介,維護連接約束
相關模式(Related Patterns)#
- Facade:提供子系統的便捷介面,協定是單向的;而 Mediator 的協定是雙向的,支援 colleague 之間的合作行為
- Observer:Colleague 可使用 Observer 模式與 mediator 通訊