6-4.【架构设计】VIPER 中,Interactor 和 Presenter 的边界如何划分才不会“反向依赖”?

2 阅读2分钟

一、VIPER 里 Interactor 和 Presenter 的职责

核心职责
Interactor纯业务逻辑 + 数据处理(网络请求、数据库、计算) 不关心 UI 或视图状态
PresenterUI 表示逻辑 + 视图事件处理 把业务数据转成 ViewModel / 展示模型
关系原则单向依赖:Presenter 可以调用 Interactor,但 Interactor 不直接依赖 Presenter

⚠️ VIPER 核心理念:依赖倒置 + 单向流
业务逻辑层(Interactor)不应该知道 Presenter 或 View 的存在。


二、为什么容易反向依赖

在实践中常见的反向依赖情景:

class UserInteractor {
    var presenter: UserPresenter?  // ❌ 直接持有 Presenter
    func fetchUser() {
        let user = api.getUser()
        presenter?.didFetchUser(user)  // ❌ Interactor 调用 Presenter
    }
}

问题:

  1. Interactor 知道了 Presenter,违反 VIPER 的依赖倒置原则
  2. Presenter 和 Interactor 相互持有 → 循环依赖
  3. 当需要单元测试 Interactor 时,必须提供 Presenter mock → 耦合高

三、正确划分边界:协议 + 单向回调

1️⃣ Interactor 不直接依赖 Presenter,而依赖协议

protocol UserInteractorOutput: AnyObject {
    func didFetchUser(_ user: User)
}

class UserInteractor {
    weak var output: UserInteractorOutput?  // 弱引用,避免循环
    func fetchUser() {
        let user = api.getUser()
        output?.didFetchUser(user)
    }
}
  • Interactor 只依赖协议
  • Presenter 实现协议
  • 单向依赖:Presenter → Interactor

2️⃣ Presenter 调用 Interactor

class UserPresenter: UserInteractorOutput {
    private let interactor: UserInteractor
    init(interactor: UserInteractor) {
        self.interactor = interactor
        self.interactor.output = self  // 单向回调
    }
    
    func loadUser() {
        interactor.fetchUser()  // 调用 Interactor
    }
    
    // MARK: - UserInteractorOutput
    func didFetchUser(_ user: User) {
        let viewModel = UserViewModel(name: user.name.uppercased())
        view?.display(user: viewModel)
    }
}
  • Presenter 调用 Interactor → 业务请求
  • Interactor 通过 协议回调 → Presenter 收到结果
  • Interactor 不知道 Presenter 存在,只依赖 UserInteractorOutput 协议

3️⃣ 优势

  1. 单向依赖

    • Presenter → Interactor
    • Interactor → 协议(不依赖 Presenter)
  2. 测试友好

    • Interactor 可以独立测试,只用 mock UserInteractorOutput
  3. 解耦清晰

    • Interactor 不管 View 或 Presenter 如何展示数据
    • Presenter 只处理 UI 表示逻辑

4️⃣ 总结原则

原则做法
依赖倒置Interactor 依赖协议,不依赖 Presenter
单向数据流Presenter 调用 Interactor,Interactor 用协议回调结果
弱引用 / 单向回调避免循环引用
UI逻辑隔离Interactor 不处理 ViewModel / UI 展示逻辑

核心思想一句话:Interactor 做“干净的业务”,Presenter 做“干净的 UI”,中间靠协议桥接,不直接握手