CleanSwift架构中,Presenter是否可直接调用Router的函数?
这是个非常务实的问题——CleanSwift的官方架构图里确实没画出Presenter到Router的直接连线,但这不代表绝对禁止这种调用,关键要看你怎么平衡架构规范和实际开发效率。
先说说官方推荐的"正统"流程
CleanSwift的经典设计是让Presenter通过回调(闭包、协议)通知ViewController,再由ViewController调用Router的方法。这么做的核心是保持Presenter的"纯粹性":它只负责把Interactor返回的数据转换成UI可展示的状态,不直接耦合导航逻辑,这样Presenter的单元测试会更简单(不需要mock Router,只需要mock回调即可)。
举个正统写法的例子:
// Presenter 代码 func presentNavigationTrigger() { viewController?.navigateToOtherScene() } // ViewController 代码 func navigateToOtherScene() { router?.routeToOtherView() }
直接调用Router的合理性场景
如果你的场景非常简单——比如只是单纯跳转到另一个视图控制器,没有复杂的页面状态传递或前置业务判断——那直接让Presenter持有Router引用并调用routeToOtherView()是完全可以接受的。很多实际的CleanSwift项目都会这么做,因为它能减少一层不必要的转发代码,让逻辑更直接。
这么做的时候需要注意两个点:
- 确保Presenter对Router的引用是弱引用,避免循环引用(毕竟Router通常持有ViewController,而ViewController又持有Presenter)。
- 让Router的路由方法保持单一职责,只处理导航逻辑,业务判断还是要放在Presenter里完成。
示例代码:
// Presenter 代码 weak var router: SomeSceneRouter? func handleNavigationRequest() { // 先完成业务判断 guard userHasPermission else { return } // 直接调用路由方法 router?.routeToOtherView() }
需要谨慎的情况
如果你的导航逻辑依赖ViewController的状态(比如需要传递当前页面的UI组件引用、依赖页面的生命周期状态),或者路由操作有复杂的前置UI交互(比如需要先弹框确认),那还是建议通过ViewController转发。毕竟ViewController才是UI层的持有者,更适合处理这类和UI紧密绑定的导航前置操作。
最后总结
CleanSwift的架构是指导原则而非刚性规则,只要你能保持各层职责清晰、代码可维护,直接调用Router完全没问题——架构的最终目的是提升开发效率和代码质量,而不是为了遵守规则而遵守规则。
内容的提问来源于stack exchange,提问作者Sazzad Hissain Khan

