转载

再谈MVP模式

为什么写这篇文章

之前在CocoaChina上投过一篇iOS基于MVC的项目重构总结。时过一年,现在回头再看,发现当初对于MVP的理解十分浅薄,再加上这几天在论坛上又看到了谈MV“X”模式的文章,发现有些文章其实还是犯了和我当初一样的错误. 为了对被我误导过的同学负责, 所以才有了这篇文章.

声明一下, 作者并不是架构师,也不是所谓的大神. 此文仅仅为一篇学习总结.

注: 本文谈论的MVP都指的是Passive View模式.

现阶段我理解的MVP

作为一名移动端开发者,我对软件质量的追求是稳定,流畅,可扩展.

无论我们使用何种架构进行开发, 目的都可以总结为两点: 缩短开发周期(不加班),降低维护成本(不加班).

MVP上承MVC, 下启MVVM, 可以说理解了MVP,就对整个MV”X”模式有了一个基本的了解.

在我现阶段的理解中, MVP其实并不是一种软件架构模式, 而是为了解决GUI开发过程中代码组织和职责规划的问题才总结出来的一套开发方法. MVP解决的只是”用户交互”-“数据处理”-“界面更新”这三者之间的问题.

  • Model: 数据层, 从本地数据库或者服务器获取并处理数据, 然后将数据反馈给presenter;

  • Presenter: 业务处理层, 接收处理View传递过来的用户交互事件, 从Model层获取数据后进行业务逻辑处理, 然后更新View;

  • View: 展示层, 将所有的交互事件传递给presenter处理, 自身只提供更新数据的接口(对iOS来说, ViewController显示也属于View层).

整个交互流程看起来大致是这样的:

用户交互->View获得交互事件->View将事件转发给Presenter->Presenter调用Model获取新数据->Presenter将数据推送给View进行展示

严格来说, 三者之间的交互应该全部通过Interface来完成, 但在实际的开发中, 为了减少代码量, 有时会直接在.h文件中定义某些交互方法. 但是”Presenter将数据推送给View进行展示”这一层的交互应该严格使用Interface来完成.

使用MVP中遇到的问题

就如上面的示例那样, 网上大部分谈论MV”X”模式所用的示例都是一个非常简单的界面, 如果实际使用MVP开发过程中往往会遇到复杂的多的问题.

V-P交互

View没有处理用户交互事件的能力, 而是将交互事件转发给Presenter进行处理, 注意上面的例子, Presenter暴露给View调用的方法应该都是没有返回值的, 更不能使用block回调. Presenter在业务逻辑处理完成后, 通过Interface将数据推送给View进行更新展示.

否则就犯了最常见的错误, 将Presenter单纯的当做View调用Model的一个中介, 那此时的Presenter仅仅是一个Proxy而已. 失去了使用MVP的意义, 无法对Presenter进行不依赖UI环境的单元测试, View也丧失了复用性.

P-P交互

另一种常见情况是当父子视图都存在各自的Presenter时, 子视图获取了用户交互事件, 但子视图的Presenter不具备处理该交互事件的能力, 此时, 需要子视图的Presenter将交互事件传递给更上一级或多级视图的Presenter进行处理.

一个具体的场景是, 在ViewController的根View的子视图中存在用户交互, 而且需要进行页面跳转, 但是继承自UIView的自定义控件是不能使用modal或push方法的. 这时就需要将事件传递到拥有页面跳转能力的根ViewController. 所以在根ViewController要实现的Interface中会包含一个@require的方法负责跳转, 其Presenter接受子视图发出的页面跳转通知, 参数就是已经包装好的目标界面, 然后调用View的相关方法实现跳转.

V-V交互

View和View的交互更多体现在动画场景中. 比如,两个view需要进行联动, 其中一个view接收到用户交互之后frame会发生变化(width收缩), 而另一个view的x是相对于第一个view的width布局的.

在这种情况下, 由于MVP的响应事件应该严格规范到相应的presenter中, 如果不涉及到业务逻辑, 两个view的Presenter通过通知进行沟通, 同步两者的收缩或展开(这时两个view的Interface中都会有shrink和expansion两个方法).

如果这两个view的状态和某个业务逻辑参数相关(比如关注状态), 则应该通过持有该状态的Model发出业务状态改变的通知, 各个presenter接受该参数, 然后处理各自的状态, 这样两个需要联动的view之间就不需要直接通讯了.

最近一直在打王者荣耀, Demo也懒得写了. 代码永远要自己写才能想的更深入, 欢迎探讨交流.

参考链接:

正文到此结束
Loading...