前言
接触 Android 开发已有一段时间。
刚开始学习时(大概2017年底),每个星期都会做一个小小的项目,类似于商品浏览页面+购物车、本地音乐播放器之类的。那时候敲代码只求把功能实现出来,逻辑什么的都写在 activity/fragment 里,好在项目量级太轻,不会有什么"代码不优美"的观感。
2018年寒假待在家的时候,因为不想让自己太咸鱼所以打算开发一个让用户分享语录的社区APP。然后什么前期规划都没有,直接创建项目开始编写第一个界面。那个时候基本是想到什么新功能就开始查资料,然后跟着学习、实践,所有的业务代码都放在 activity/fragment 里。随着功能的不断扩展,每个 activity/fragment 里的代码也不断膨胀,加上我是个不太喜欢注释的人,所以代码看起来就是乱糟糟的一大堆。不过我当时没有意识到这个问题,感觉能实现出自己想要的功能就厉害得不行了哈哈哈。寒假结束后我的项目也差不多搞完了,之后就放着不管了。直到大三下学期的期末需要提交一个项目,于是我又把这个APP的代码翻出来,打算做一些功能优化。结果一打开代码我就对自己产生了怀疑,实在不想承认是自己写的。总体感觉就是代码很繁冗,并且结构不清晰(除了作者之外应该没啥人愿意看),还有很多本可以复用的逻辑没有解耦。反正后期的维护和优化都变得十分困难,也不是难吧,就是要花精力去梳理代码,这点还挺让人烦躁的。
随便放个当初的代码截图,感受一下画风 (〃-ー-)ノ
言归正传。其实我上面用的模式都是最传统的 MVC 吧。在这个模式中,Activity 不但承担着 View 的角色,还包含了 Controller 的大部分逻辑。在项目量级较轻时,这样写没有问题。但是项目规模一旦扩大,Activity 的代码就会变得臃肿,且耦合度太高,不利于持续的开发与维护。
MVP 初体验
大四上学期(2018/11)开始准备毕设 APP。因为这时候已经修完几门关于"软件工程生产周期"的课了,也实习过一段时间了(虽然是在写 JS 和 Python),接触过部门的几个项目,所以有了前期准备的意识。大概就是在编程之前先进行背景调研、原型设计、架构选型、模块划分之类的。因为有了前车之鉴,所以在选择项目的架构模式时,花了好几天的时间进行仔细考量,最终敲定了 MVP。
关于 MVP 模式,本来打算在这篇博客里详细总结一下。但是网上讲解 MVP 模式的优秀文章太多了,我觉得我既然无法青出于蓝,那也就没有必要花精力写那么多不痛不痒的内容了。简单地画了两张UML 图,谈谈我所理解的 MVP 模式吧。
定义
MVP 把 Activity 中的 UI 逻辑抽象成 View 接口,把业务逻辑抽象成 Presenter 接口,Model 类还是原来的 Model。这样子Activity的工作变得简单了,只用来响应生命周期,其他工作都丢到Presenter中去完成。从上图可以看出,Presenter 是 Model 和 View 之间的桥梁,为了让结构变得更加简单,View 并不能直接对 Model 进行操作,这也是 MVP 与 MVC 最大的不同之处。
使用步骤
从上图中可以看出,使用MVP,需要经历以下步骤:
- 创建 IPresenter 接口,把所有业务逻辑的接口都放在这里,并创建它的实现 PresenterCompl(在这里可以方便地查看业务功能,由于接口可以有多种实现所以也方便写单元测试)。
- 创建 IView 接口,把所有视图逻辑的接口都放在这里,实现类是当前的 Activity/Fragment。
- 由 UML 图可以看出,Activity 里包含了一个 IPresenter,而 PresenterCompl 里又包含了一个 IView 并且依赖了 Model。Activity 里只保留对 IPresenter 的调用,其它工作全部留到PresenterCompl 中实现。
- Model 并不是必须有的,但是一定会有 View 和 Presenter。
总之就是把 Activity 里的许多逻辑都抽离到 View 和 Presenter 接口中去,并由具体的实现类来完成。
优点
对于初学者而言,可能无法一下子理解,没关系我之前也是这样,然而动手写了几个界面逻辑后立马就熟悉了。刚开始可能会觉得文件量骤增,毕竟原来一个 Activity 就能搞定的事,现在我要写 IView + Activity + IPresenter + PresenterCompl,好烦有没有?不过随着项目工程的扩展,也就渐渐体会到 MVP 模式的好处了。
优点如下:
- 分离了视图逻辑和业务逻辑,降低了耦合。
- Activity只处理生命周期的任务,代码变得更加简洁。
- 视图逻辑和业务逻辑分别抽象到了View和Presenter的接口中去,提高代码的可阅读性。
- Presenter被抽象成接口,可以有多种具体的实现,所以方便进行单元测试。
- 把业务逻辑抽到 Presenter 中去,避免后台线程引用着 Activity 导致 Activity 的资源无法被系统回收从而引起内存泄露和OOM。
个人感受
自从使用了 MVP 模式,腰不疼了腿不酸了,毕设作品的项目代码变得更加规范简洁,后期的维护也方便很多。入职后接触的项目代码也是用的 MVP,于我而言,少了许多阅读障碍。
对于 MVP 的使用,其实也没必要按步骤写的那样,必须定义那么多接口。比起学会如何使用,更重要的是掌握它的核心思想,融会贯通。无论是 MVC、MVP、MVVM,事实上都没有绝对的孰优孰劣,要根据实际的项目进行考量,有时候甚至可以多种模式混用(假若有多个不同业务模块)。总而言之,具体问题具体分析。唯一可以确定的是,选择了适合的架构模式,后期的开发之路就会平坦很多。