iOS中的设计模式(十)- 中介者模式(从播放器场景理解中介者模式)

一. 引言

当我们第一次读到中介者模式(Mediator Pattern)时,可能会觉得有点抽象,有点啰嗦、脱离实际业务。

而我们这篇博客我打算不从教科书角度出发,而是从一个非常清晰的真实iOS业务场景中,一步一步来演示中介者模式在实际开发中的使用,以及它所解决的问题。

中介者模式:用一个对象来封装一些列对象的交互方式,中介者使各个对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

二. 业务场景描述

我们就以一个十分场景的业务场景为例,一个视频播放器的播放页,播放页的页面功能通常会比较复杂,除了播放功能外往往还需要:

  • 处理字幕信息。
  • 处理弹幕信息。
  • 处理拖拽及点击手势。
  • 进行埋点统计。

等等。

我们就提出来4个功能,这4个功能呢分布于不同的四个类当中:

  1. PlayerView:负责视频的播放功能。
  2. ControlBarView:负责视频控制功能,比如播放、暂停、拖拽进度、拖拽亮度、音量等等。
  3. SubtitleView:负责处理字幕功能。
  4. AnalyticsManager:负责埋点统计。

一个非常简单的需求场景,当用户点击播放按钮时:

  • PlayerView 开始播放视频。
  • ControlBarView 按钮状态变为播放中。
  • SubtitleView 字幕开始更新。
  • AnalyticsManager 上报一次播放埋点。

这听起来确实很容易,我们甚至不需要考虑就把代码写出来。

三. 不使用中介者的写法

即使不使用中介者,我们也可以实现这样的需求。

比如ControlBarView 控制视图内的实现:

Swift 复制代码
class ControlBarView {
    // 播放视图
    var playerView: PlayerView?
    // 字幕视图
    var subtitleView: SubtitleView?
    // 埋点管理类
    var analytics: AnalyticsManager?
    
    /// 播放按钮点击
    func playButtonTapped() {
        playerView?.play()
        subtitleView?.start()
        analytics?.track(event: "play")
    }
}

这表面上没有什么问题,但是实际上:

  • ControlBarView 知道太多的对象了。
  • 所有的联动逻辑都写死在了View里面。
  • 新增或者删除一个响应方,都需要调整这个View的代码。

UI现在承担了一个业务调度者的角色,这是非常不妥当的一个行为。

就目前的实现而言:

  1. UI组件之间强耦合。
  2. 交互逻辑分散在各个View当中。
  3. 后续需求一旦开始复杂将会需要越来越多的代码和逻辑,会变得开始失控。

那么 中介者 要解决的就是这个问题。

四. 引入中介者(PlaybackMediator)

接下来我们开始引入中介者,为了更方便理解,我们尽量将内容简单化。

4.1 定义中介者协议

我们采用协议的形式来定义作为中介者,需要实现的方法:

Swift 复制代码
protocol PlaybackMediator: AnyObject {
    func playTriggered()
}

4.2 中介者的具体实现

接下来我们需要定义一个中介者类,并循序中介者协议。与此同时该对象内还应该引用到所有同事对象。我们把前面几个相互协作的对象就成为同事对象。

Swift 复制代码
class PlaybackCenter: PlaybackMediator {
    // 播放视图
    let playerView: PlayerView
    // 控制视图
    let controlBar: ControlBarView
    // 字幕视图
    let subtitleView: SubtitleView
    // 埋点管理
    let analytics: AnalyticsManager

    init(playerView: PlayerView,
         controlBar: ControlBarView,
         subtitleView: SubtitleView,
         analytics: AnalyticsManager) {
        self.playerView = playerView
        self.controlBar = controlBar
        self.subtitleView = subtitleView
        self.analytics = analytics
    }

    // 播放方法
    func playTriggered() {
        playerView.play()
        controlBar.updatePlayingState()
        subtitleView.start()
        analytics.track(event: "play")
    }
}

所有的联动都将集中到这个类当中。

4.3 同事对象只和中介者通讯

而同事对象之间将不再进行通讯,而是直接与中介者进行通讯。

ControlBarView
Swift 复制代码
class ControlBarView {
    weak var mediator: PlaybackMediator?

    func playButtonTapped() {
        mediator?.playTriggered()
    }

    func updatePlayingState() {
        print("UI 更新为播放中")
    }
}
PlayerView
Swift 复制代码
class PlayerView {
    func play() {
        print("开始播放视频")
    }
}
SubtitleView
Swift 复制代码
class SubtitleView {
    func start() {
        print("字幕开始")
    }
}

五. 结构变化分析

在我们没有使用中介之间呢我们的结构是通过 ControlBarView 来连接 playerView、subtitleView和 analytics。

而引入中介之后呢UI组件之间不再有任何关联,ControlBarView 链接 PlaybackMediator, 而PlaybackMediator链接playerView、subtitleView和analytics。

就实现了 组件之间零耦合、UI 只负责 UI、业务联动集中管理。

六. 结语

在 iOS 的世界里,中介者其实一点也不陌生。UITableViewDelegate、UICollectionViewDelegate、Coordinator / Router,以及 MVVM-C 中的协调层,它们都有一个非常一致的特征:

页面或组件本身,不负责跳转、不负责调度,只负责"汇报事件"。

真正决定"接下来该谁做什么"的,是那个站在中间的角色。也正因为如此,当你在项目中逐渐遇到这些信号时------一个类开始同时持有多个对象,View 或 ViewModel 里出现明显的业务流程判断,改一个交互却需要同时修改好几个文件,其实并不是你代码写得不够好,而是复杂度已经在提醒你:需要一个中介者了

当然,中介者模式也并非没有代价。最常见、也最危险的坑,就是它悄悄膨胀成一个 God Object:一个 Mediator 几百行代码,if / switch 满天飞,所有事件都往里塞,最终变成新的"混乱中心"。

更合理的做法是:按业务场景拆分中介者,一个中介者只负责一个清晰、可描述的协作流程,不要害怕多几个 Mediator 类------它们恰恰是在帮你控制复杂度,而不是制造复杂度。

所以,中介者模式并不是为了"用设计模式而用设计模式"。而是当你发现:

  • 一个类知道得太多
  • 一个改动牵一堆地方
  • View 里开始写本不属于它的业务判断

那你其实已经站在了需要中介者模式的边缘。

感谢大家阅读。

相关推荐
Geoking.2 小时前
【设计模式】组合模式(Composite)详解
java·设计模式·组合模式
刀法孜然2 小时前
23种设计模式 3 行为型模式 之3.6 mediator 中介者模式
设计模式·中介者模式
Yu_Lijing3 小时前
基于C++的《Head First设计模式》笔记——单件模式
c++·笔记·设计模式
Geoking.3 小时前
【设计模式】外观模式(Facade)详解
java·设计模式·外观模式
点云SLAM3 小时前
C++设计模式之单例模式(Singleton)以及相关面试问题
c++·设计模式·面试·c++11·单例模式(singleton)
GISer_Jing18 小时前
AI Agent 目标设定与异常处理
人工智能·设计模式·aigc
蔺太微18 小时前
组合模式(Composite Pattern)
设计模式·组合模式
鱼跃鹰飞20 小时前
DDD中的防腐层
java·设计模式·架构
会员果汁21 小时前
15.设计模式-组合模式
设计模式·组合模式