MVP模式在Android实际项目中的应用和优化

注:本文阅读需要对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中的代码。

之前看过三个例子,非常好的诠释了这三点:

  1. 如果哪天,APP要升级,界面,风格,或者提示的文案,颜色等要修改,但是展示的数据源没有变化,这时候,我只需要修改View层的代码,其他代码不需要修改。因为把数据处理业务逻辑都融合到View中的话,修改起来会比较麻烦,改动的代码会很多。
  2. 如果哪天,有更好到网络框架出现,你很想换掉原先的网络框架,那么你原先写的Model层代码就要做相应的修改,这样,你只需要对Model部分进行修改,不需要对Presenter和View进行修改。
  3. 假设业务逻辑也要改了,那只需要修改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. 爆炸式增长的类和接口,原先的1,2个或者2,3个类,现在变成6,7个甚至10几个。
  2. 复用的时候可能造成接口的冗余。
  3. Presenter持有着View的强应用,在请求网络数据等耗时操作的时候,Activity可能被销毁,可能会导致View无法回收,从而造成内存泄漏问题。

##MVP模式在项目中的优化 MVP的优点还是有很多的,总的来说是利大于弊,所以我们的优化肯定是针对缺点进行优化的。根据个人的经验,内存泄漏可以通过一些方法处理掉,所以主要是要优化缺点1和2。

####优化1: MVP的接口类,有两种写法,一种是直接写接口类,一种是通过协议类,什么意思呢?具体见下图: 总的来说,直接写接口类,1个模块就会比通过协议类多1到2个接口类,查找接口和引用的时候也不够方便,通过实际尝试,个人还是比较推荐协议类写法,并且谷歌官方的demo和推荐MVP写法是通过协议类方式

  1. 直接接口写法(这里引用一下别人的demo图)

  1. 协议类写法(摘自实际开发项目)

####优化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,只要适合自己,适合项目,用的好就行了。

转载于:https://juejin.im/post/5a321db4f265da430c11d5bf

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/368470.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

将训练集构建成ImageNet模型

以下程序实现将训练集构建为ImageNet模型,训练集图片为56个民族 import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintWriter;public class createTxt {public static void createClassInd(){//56个…

CSS基本知识(慕课网)

1、注释 注解&#xff1a;CSS中注释/*这里是注释的文字*/ HTML中注释<!--这里是注释的文字--> 2、外部式css样式&#xff0c;写在单独的一个文件中 注解&#xff1a; 外部式css样式(也可称为外联式)就是把css代码写一个单独的外部文件中&#xff0c;这个css样式文件以“…

JMS和Spring:有时很重要的小事情

JmsTemplate和DefaultMessageListenerContainer是用于访问JMS兼容MOM的Spring帮助器。 他们的主要目标是在JMS API之上形成一层&#xff0c;并处理诸如事务管理/消息确认之类的基础结构&#xff0c;并隐藏JMS API的某些重复和笨拙的部分&#xff08;保留在那里&#xff1a; JMS…

python 音速_webpack多页应用架构系列(十一):预打包Dll,实现webpack音速编译

前言上文说到我们利用webpack来打包一个可配置的bootstrap&#xff0c;但文末留下一个问题&#xff1a;由于bootstrap十分庞大&#xff0c;因此每次编译都要耗费大部分的时间在打包bootstrap这一块&#xff0c;而换来的仅仅是配置的便利&#xff0c;十分不划算。我也并非是故意…

whereis 命令

可以用来查看命令的路径&#xff0c;安装在哪里 whereis命令是定位可执行文件、源代码文件、帮助文件在文件系统中的位置 [rootsalt-server-192 a]# whereis mysql mysql: /usr/bin/mysql /usr/lib64/mysql /usr/share/mysql /usr/share/man/man1/mysql.1.gz 转载于:https://ww…

css实现3D立方体旋转特效

先来看运行后出来的效果 它是在不停运行的一个立方体 先来看html部分的代码 <div class"rect-wrap"> <!--舞台元素&#xff0c;设置perspective&#xff0c;让其子元素获得透视效果。--><div class"container"> <!-- 容器&#…

Eclipse中的Tomcat:6个流行的“如何”问题

学习新技术总是一个艰难的过程。 当您尝试学习将要相互交互的两种技术时&#xff0c;此过程将变得更加困难。 Tomcat和Eclipse是Java EE开发中最流行的先决条件。 因此&#xff0c;要成为一名专业的开发人员&#xff0c;您需要知道如何使用此对执行最需要的操作以及如何进行一些…

adc分辨率和精度的区别_科普 | 传感器的灵敏度、分辨率和精度三者之间有何区别?...

传感器作为一种检测装置&#xff0c;具有微型化、数字化、智能化、多功能化、系统化、网络化的特点。在现代工业生产尤其是自动化生产过程中&#xff0c;需要各种传感器来监视和控制生产过程中的各个参数&#xff0c;使设备工作在正常状态或最佳状态&#xff0c;并使产品达到最…

Node08 - 配置模板引擎 -(route)

1、配置模板引擎 &#xff08;01&#xff09;、输出什么东西        //view engine&#xff1a;视图模板引擎(以何种方式呈现给用户) > 指定输出html           server.set(view engine, html); &#xff08;02&#xff09;、模板文件放在哪 //views: 指定好…

for循环与foreach的区别

for循环与foreach的区别 foreach 依赖 IEnumerable. 第一次 var a in GetList() 时 调用 GetEnumerator 返回第一个对象 并 赋给a, 以后每次再执行 var a in GetList() 的时候 调用 MoveNext.直到循环结束. 期间GetList()方法只执行一次. 1 2 3 4 5 6 7 8 9 10 11 12 13 fo…

SVN 定时 更新代码 Demo

1. 涉及技术&#xff1a;Winservice: 用system身份后台跑&#xff1b; Quartz&#xff1a;定时任务&#xff1b; SVN 2. 思路&#xff1a;Quartz定时调用cmd 程序,执行SVN update 命令,整个程序寄宿在Winservice3. 步骤&#xff1a;1&#xff09;service 用local system账户安…

如何在Jackson中使用PropertyNamingStrategy

Jackson api被广泛用于将json转换为Object并将Object转换为JSON。因此&#xff0c;如果您有json字符串并想在java对象中进行转换&#xff0c;请创建与json中的字段相同的bean的字段名。 Jackson在将json字段映射到java对象字段时遵循标准的bean约定&#xff0c;但是如果您有一个…

现代软件工程--阅读笔记

团队对个人的期望 &#xff08;1&#xff09;交流&#xff1a;能有效的和其他队员交流&#xff0c;从大的技术方向&#xff0c;到看似微小的问题。 &#xff08;2&#xff09;说到做到&#xff1a;“按时交付” &#xff08;3&#xff09;接受团队赋予的角色并按角色要求工作:团…

Linux上的HotSpot GC线程CPU占用空间

以下问题将测试您对Linux操作系统上运行的Java应用程序的垃圾回收和高CPU故障排除的知识。 当调查过多的GC和/或CPU利用率时&#xff0c;此故障排除技术尤其重要。 它将假定您没有访问高级监视工具的能力&#xff0c;例如Compuware dynaTrace甚至JVisualVM。 将来会介绍使用此类…

tornado-简介和原理

tornado-设计初衷 1. 追求小而精 2. epoll IO多路复用和协程 3. 支持WebSocket 4. 单线程程序(GIL限制&#xff0c;本身某种意义上不启动多进程就是单线程程序) # Python GIL介绍详情 tronado应用场景 1. 大量的http请求连接(大量的用户请求&#xff0c;要求并发性和高性能) tr…

mysql5.6.13_MySQL-5.6.13解压版(zip版)安装配置教程

1、将mysql-5.6.13-winx64.zip 解压到D:\mysql-5.6.13\目录。2、清理里面的调试文件打开这个目录&#xff0c;发现里面的文件夹和文件跟一个安装好后的MySQL基本没有区别。可能你会很郁闷&#xff0c;这个MySQL5.6.13居然有1.04GB&#xff0c;呵呵&#xff0c;仔细一看你就会发…

前端学习笔记--HTTP缓存

原文地址&#xff1a;https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hlzh-cn 缓存并重用之前获取的资源的能力是性能优化的一个关键方面。 每个浏览器都自带了 HTTP 缓存实现功能&#xff0c;只需要确保每个服务…

socket programming

进行 socket programming开始要做的工作&#xff1a; On Linux: 以下是client代码&#xff0c;使用TCP&#xff0c;注意网络字节序&#xff1a; 1 #include <sys/socket.h> 2 #include <netinet/in.h> 3 #include <arpa/inet.h> 4 int main() 5 { 6 …

如何用Veripacks替换构建模块

比较下面的两棵树。 在这两种情况下&#xff0c;目标都是拥有一个具有两个独立模块&#xff08; frontend和reporting &#xff09;和一个共享/公用模块&#xff08; domain &#xff09;的应用程序。 frontend的代码不应访问reporting代码&#xff0c;反之亦然。 两个模块都可…

JS的DOM和BOM

* JavaScript分三个部分: ECMAScript标准:JS的基本的语法DOM:Document Object Model --->文档对象模型----操作页面的元素BOM:Browser Object Model----->浏览器对象模型---操作的是浏览器一、DOM对象 文档:把一个html文件看成是一个文档,由于万物皆对象,所以把这个文档看…