注:本文阅读需要对MVP模式有基本了解。 MVP模式已经出现有很长一段时间了,但是火起来是这两年的事情。
关于MVP的概览,介绍,乃至于教程,Demo,实例,网上都有很多,我也有一篇文章专门收录了一些关于MVP的资料,起码现在很多朋友对表现层(Presenter),视图层(View),模型协议类,接口这些词并不陌生了。 很长一段时间,出去面试的筒子们经常会被问到一个问题:知道谷歌四件套么?(MVP, Dagger2 ,retrofit ,RxJava) 确实新项目应用四件套,带来的好处是大大的,当然,也会有一些问题。我做的上个项目是个新项目,所以就应用了谷歌四件套,到目前已经一年多了,所以稍微总结一下。在实际项目中是怎么使用MVP,带来的好处,以及怎么优化。
##几句话介绍和总结MVP模式和MVC模式 先简单介绍和对比下MVC和MVP,下面是摘自百度百科关于MVP的介绍中的图,个人再加了一些标注,这两张图还是很经典的: 【MVC】:MVC就不用多说,具有悠久的历史。这里View一般是指xml,html;Controller一般是指activity,fragment。 好处就是写起来方便并且快;缺点就是东西多的时候,activity/fragment很重,基本上配合数据、业务,然后控制view层显示隐藏交互等所有的逻辑都在里面,代码动辄上千行,维护较困难,耦合度高,改个bug或者需求眼睛花,找不到位置,若是没有注释,那真的就是……你懂的;不过也有一些项目把controller层单独抽出来, View不直接依赖 Model,而是把所有业务逻辑都放在 Controller 中处理,而 View 只和 Controller 交互。
【MVP】:MVP主要就是把Model和View进行了分离,通过presenter去连接,主要的程序逻辑在Presenter里实现,并且Presenter与具体的View是没有直接关联的,而是通过定义好的接口(Interface Presenter;Interface View)进行交互,从而使得在变更View时候可以保持Presenter的不变。 总之,View很薄(activity和fragment代码很少),presenter处理逻辑,代码有可能会比较多,具体根据业务定。然后View只有简单的Set/Get的方法(Set-->设置界面信息/Get-->获取界面信息),决不允许直接访问Model。
##MVP模式的优点 根据个人项目经验,总结一下主要有如下几个:
- 结构清晰
- 代码解耦
- 复用性高
- 单元测试方便
- 适用于快速迭代开发
####结构清晰 由于MVP中,模型与视图完全分离,View,Model,Presenter各司其职,所以代码看上去会非常清爽
- view中单纯的控制视图即可(例如显示隐藏修改数据什么的);
- model中只处理数据;
- presenter中是一个个的方法体,只处理逻辑,不用关心视图怎么处理,数据如何获取。
这里贴几张项目中实际的代码图,虽然是很简单的类,但是可以感受到结构有多清晰。
####代码解耦 同样由于模型与视图完全分离,我们可以修改视图而不影响模型。
- 1:我们需要修改视图相关的,直接在View层中修改就行了,不需要修改Model与Presenter层;
- 2:我们需要修改Model相关的,比如网络框架或者数据库框架,则只需要修改Model层,不需要修改View层和Presenter层。
- 3:我们需要根据不同的参数和规则,修改业务或者逻辑,则直接在Presenter层中修改就行了,通过mView.XXX连接到view层,不需要修改View层和Model中的代码。
之前看过三个例子,非常好的诠释了这三点:
- 如果哪天,APP要升级,界面,风格,或者提示的文案,颜色等要修改,但是展示的数据源没有变化,这时候,我只需要修改View层的代码,其他代码不需要修改。因为把数据处理业务逻辑都融合到View中的话,修改起来会比较麻烦,改动的代码会很多。
- 如果哪天,有更好到网络框架出现,你很想换掉原先的网络框架,那么你原先写的Model层代码就要做相应的修改,这样,你只需要对Model部分进行修改,不需要对Presenter和View进行修改。
- 假设业务逻辑也要改了,那只需要修改Presenter层就行,不需要修改其他两个模块。
同样,在进行分模块划分分工合作的时候,根据不同的人擅长的点不同,可以进行多元化的分模块。 在MVC模式中,一般是每个人负责一个模块,包括Model,View和Controller层。 当然在MVP中,也可以这样划分,一个人负责一个模块的整个MVP部分。但是我们多了一种选择:一个擅长写视图的人负责所有的View层代码,一个擅长写逻辑的负责所有的P层代码。
- 具体实现一般是:一个架构师设计好项目架构和写好基本的common部分和MVP类,并写好基本方法和暴露的借口(这样有利于规范方法名等)。然后由开发人员在各自模块工作,根据暴露的接口和规范,写逻辑的专门写逻辑,写视图的专门写视图。
####复用性高 为什么这么说呢?因为所有的交互和逻辑都发生Presenter内部,所以我们可以将一个Presenter用于多个View层,不用修改Presenter中的逻辑,就算有细微区别的的地方可以通过方法重载等方式处理,从而达到高效利用模型。并且做过开发的一半都知道一件事,就是视图层的修改远比逻辑层的来的频繁,所以逻辑层Presenter不用动是一件很幸福的事。
####单元测试方便 由于Presenter是纯逻辑层(纯Java代码),里面没有Android代码,所以我们可以直接对Presenter写Junit测试(可以脱离用户接口来测试这些逻辑)。
####适用于快速迭代开发 基于以上的优点,MVP模式非常适用于快速迭代的项目,敏捷开发模式,能充分应对多变的需求。
##MVP模式的缺点 用辩证的角度看世界,凡事有利必有弊,关于MVP的缺点:
- 爆炸式增长的类和接口,原先的1,2个或者2,3个类,现在变成6,7个甚至10几个。
- 复用的时候可能造成接口的冗余。
- Presenter持有着View的强应用,在请求网络数据等耗时操作的时候,Activity可能被销毁,可能会导致View无法回收,从而造成内存泄漏问题。
##MVP模式在项目中的优化 MVP的优点还是有很多的,总的来说是利大于弊,所以我们的优化肯定是针对缺点进行优化的。根据个人的经验,内存泄漏可以通过一些方法处理掉,所以主要是要优化缺点1和2。
####优化1: MVP的接口类,有两种写法,一种是直接写接口类,一种是通过协议类,什么意思呢?具体见下图: 总的来说,直接写接口类,1个模块就会比通过协议类多1到2个接口类,查找接口和引用的时候也不够方便,通过实际尝试,个人还是比较推荐协议类写法,并且谷歌官方的demo和推荐MVP写法是通过协议类方式
- 直接接口写法(这里引用一下别人的demo图)
- 协议类写法(摘自实际开发项目)
####优化2: 要灵活应用MVP模式,不是每个类都需要用MVP模式去写,在项目中更要灵活变通。 例如:如果类比较简单,处理的东西不多,完全可以通过MVC模式,又快又方便,贴一张实际项目中的图: 可以看到我们没有写相关的Interface View、Interface Presenter 和Interface Model。加上Import,Butterknife,一共才200来行。因为只有一个网络请求,几个简单的点击事件,所以完全没有必要搞很多类引用来引用去。
####优化3: 由于类和接口众多,所以模块A的Presenter并不复杂,代码也不多,模块B和A之间又有一些关联或者大同小异,就尽量让模块B复用模块A的Presenter和Contract,通过继承,多态,方法重载等方式处理,这样可以减少很多类和接口,结构也不会很复杂,看上去也更清爽。
例如:我的项目中有两种课程类型(类型A和类型B)的页面,但是仅仅是数据源不一样,所以我就统一放在一个Presenter中处理了。
##写在最后 MVP模式确实是一个非常优秀的架构模式,但是每个人、每个项目,用起来都是不一样的,用法写法也是千千万万。但总归一句话:没有最好的架构,只有最适合的架构。一定要灵活变通,举一反三,不管是MVC、MVP还是MVVM,只要适合自己,适合项目,用的好就行了。