软件设计

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 vs Observer:有什么区别?

很多人确实容易混淆这两者。

简单总结一下区别:

分类 Mediator Observer
方向 集中管理多对多通信 一对多通知(发布-订阅)
关系 对象通过 Mediator 进行交互 被观察者通知观察者
重点 复杂的相互“协调” 状态变化的“传播”

简单来说,Observer 是单方面通知“我变了!”的一方。

Mediator 则会判断“这种情况下谁应该做什么?”,并协调对象之间的关系。

在 Swift 中,Combine 和 NotificationCenter 更接近 Observer 类型,而 Mediator 通常需要自行实现。


常见问题(Q&A)

问:如果 Mediator 变得太大怎么办?

由于逻辑集中在这里,Mediator 很容易变得臃肿。可以按功能拆分成多个 Mediator,或将内部逻辑分离到独立的辅助对象中。

问:一定要使用 weak 吗?

是的。如果参与者和 Mediator 彼此强引用,就会因循环引用产生内存泄漏。请像示例一样将一方设为 weak。

问:SwiftUI 中也能使用吗?

可以。ViewModel 往往实际上扮演着 View 之间的 Mediator 角色,可以通过一个 ViewModel 自然地协调多个 View 的状态。

画出一个 Mediator、理清关系后,脑子一下清爽了
画出一个 Mediator、理清关系后,脑子一下清爽了

如果对象彼此纠缠,已经让你不敢修改代码,不妨试试加入 Mediator 模式。

只需建立一个 Mediator,就能让每个对象轻量许多,之后添加功能也更安心。

推荐你把今天的示例代码原样应用到一个小项目中。亲自写一遍,很快就能掌握。😊

延伸阅读