軟體設計

Swift Mediator 模式完整整理(將物件間通訊交給中介者)

如果你曾經把 iOS App 稍微做大一些,應該遇過這種時刻。

閱讀 4 分鐘
Swift Mediator 模式完整整理(將物件間通訊交給中介者) 封面圖

如果你曾經把 iOS App 稍微做大一些,應該遇過這種時刻。

一個畫面有五、六個 View,A 一改變,B 也要改;B 改變後,C 還得跟著調整。

不知不覺間,View 彼此直接參考,像線團一樣糾纏在一起。

這時候,Mediator 模式正好能幫你整理。

Swift Mediator 模式讓物件只和 Mediator 溝通、不直接參考彼此,藉此降低耦合度。

本文會搭配範例程式碼,說明 Mediator 模式是什麼、何時適合使用,以及如何用 Swift 實作。


什麼是 Mediator 模式?

用一句話說就是:

在需要互相通訊的物件之間放入一個中介者,讓所有溝通都經過它。

可以把它想成機場的塔台。

如果飛機彼此用無線電說「你先降落」「我先來」,就會發生重大事故。

因此每架飛機只和塔台溝通,由塔台安排順序。

這裡的飛機就是程式碼中的物件,而塔台就是 Mediator。

Mediator 模式要解決的核心如下:

  • 移除直接參考:物件 A 不必逐一知道 B、C、D
  • 集中通訊邏輯:複雜的互動規則集中在一個 Mediator
  • 提升可重複使用性:各物件彼此獨立,容易套用到其他畫面

什麼時候該使用 Mediator 模式?

它並非適合所有情境。我看到以下訊號時,會考慮導入。

當物件太了解彼此,也就是開啟一個類別後,其他物件的參考接二連三出現時。

另一種情況是,只想修改一段邏輯,卻必須同時調整多個相關物件。

常見用途整理如下:

情境 範例
複雜畫面 UI 表單輸入值變化時,多個按鈕與標籤連鎖反應
元件協調 在聊天室參與者之間轉送訊息
工作流程控制 管理付款各階段的 View 狀態

反過來,如果只有兩三個物件且關係單純,最好不要勉強使用。

否則中介者可能無端膨脹,變成「God Object」。


Swift Mediator 模式要如何實作?

以聊天室為例。參與者不是彼此直接傳訊息,而是透過聊天室(Mediator)互相傳遞。

首先定義 Mediator 必須遵守的協定,以及參與者。

// Mediator 必須遵守的規則
protocol ChatMediator {
    func send(_ message: String, from user: User)
    func add(_ user: User)
}

重點是參與者只知道 Mediator,不會直接參考其他參與者。

class User {
    let name: String
    weak var mediator: ChatMediator?  // 避免循環參考

    init(name: String) { self.name = name }

    func send(_ text: String) {
        mediator?.send(text, from: self)  // 委派給 Mediator
    }
    func receive(_ text: String) {
        print("\(name) 收到: \(text)")
    }
}

最後由 Mediator 負責實際傳送規則,也就是只把訊息廣播給寄件者以外的人。

class ChatRoom: ChatMediator {
    private var users: [User] = []
    func add(_ user: User) { users.append(user); user.mediator = self }
    func send(_ message: String, from user: User) {
        users.filter { $0 !== user }
             .forEach { $0.receive("[\(user.name)] \(message)") }
    }
}

無論使用者增加多少,都不必修改 User 類別,因為只有 ChatRoom 知道傳送規則。

大家只知道 ChatRoom,彼此互不認識
大家只知道 ChatRoom,彼此互不認識
直接執行範例程式碼並跟著輸入,很快就能掌握
直接執行範例程式碼並跟著輸入,很快就能掌握

Mediator 和 Observer 有什麼不同?

真的有很多人會把這兩者搞混。

簡單整理差異如下:

分類 Mediator Observer
方向性 將多對多通訊集中管理 一對多通知(發佈-訂閱)
關係 物件透過 Mediator 互動 被觀察者通知觀察者
重點 複雜的相互「協調」 狀態變化的「傳播」

簡單來說,Observer 是單方面通知「我變了!」的一方。

Mediator 則會判斷「在這種情況下誰該做什麼?」,負責協調彼此。

在 Swift 中,Combine 或 NotificationCenter 比較接近 Observer 類型,而 Mediator 通常需要自行實作。


常見問題(Q&A)

Q. 如果 Mediator 變得太大怎麼辦?

由於邏輯集中在其中,Mediator 很容易膨脹。此時建議依功能拆成多個 Mediator,或把內部邏輯分離到獨立的輔助物件。

Q. 一定要使用 weak 嗎?

是的。參與者和 Mediator 若彼此強參考,會因循環參考造成記憶體洩漏。請像範例一樣將其中一方設為 weak。

Q. SwiftUI 也能使用嗎?

可以。ViewModel 常常實際上扮演 View 之間的 Mediator,能自然地用一個 ViewModel 協調多個 View 的狀態。

畫出一個 Mediator、整理好關係後,腦袋清爽多了
畫出一個 Mediator、整理好關係後,腦袋清爽多了

如果物件彼此糾纏,讓你害怕動手修改程式碼,不妨試著加入 Mediator 模式。

只要建立一個 Mediator,每個物件就會輕量許多,日後新增功能時也更安心。

推薦你直接把今天的範例程式碼套用到小型專案中。親手實作後就會豁然開朗。😊

延伸閱讀