浅谈MVP架构及开发模式
MVC or MVP Pattern – Whats the difference?
Android App的设计架构:MVC,MVP,MVVM与架构经验谈
Android中的MVP
【译】Android开发中的MVP架构
介绍Activity是上帝类
首先,让我们思考下为什么在Android开发中如此迫切地需要一个清晰的架构。
该段摘自“代码大全第二版”
“避免创建神类。避免创建无所不知,无所不能的上帝类。如果一个类需要花费时间从其他类中通过Get()和Set()检索数据(也就是说,需要深入业务并且告诉它们如何去做),所以是否应该把这些功能函数更好的组织到其它类而不是上帝类中。(Riel 1996)”
上帝类的维护成本很高,你很难理解正在进行的操作,并且难以测试和扩展,这就是为什么要避免创建上帝类的黄金法则。
然而,在Android开发中,如果你不考虑架构的话,Activity类往往会越来越大。这是因为,在Android中,允许View和其它线程共存于Activity内。其实最大的问题莫过于在****Activity****中同时存在业务逻辑和UI****逻辑。这会增加测试和维护的成本。
- UI + 业务逻辑
- 多线程
- 意大利面代码:指一个代码的控制结构复杂、混乱而难以理解
- 难以测试
这是为什么需要清晰架构的原因之一。不仅会造成Activity的臃肿,还会引起其它问题,如使Activity和Fragment的生命周期变的复杂,以及数据绑定等。
什么是MVP?
MVP代表Model,View和Presenter。
- View层负责处理用户事件和视图部分的展示。在Android中,它可能是Activity或者Fragment类。
- Model层负责访问数据。数据可以是远程的Server API,本地数据库或者SharedPreference等。
- Presenter层是连接(或适配)View和Model的桥梁。
下图是基于MVP架构的模式之一。View是UI线程。Presenter是View与Model之间的适配器。UseCase或者Domain在Model层中,负责从实体获取或载入数据。依赖规则如下:
关键是,高层接口不知道底层接口的的细节,或者更准确地说,高层接口不能,不应该,并且必须不了解底层接口的细节,是(面向)抽象的,并且是细节隐藏。
同心圆将软件划分为不同的区域,一般的,随着层级的深入,软件的等级也就越高。外圆是实现机制,内圆是核心策略。
Entities:
- 可以是一个持有方法函数的对象
- 可以是一组数据结构或方法函数
- 它并不重要,能在项目中被不同应用程序使用即可
Use Cases
- 包含特定于应用程序的业务规则
- 精心编排流入Entity或者Entity流出的数据
- 指挥Entity直接使用项目范围内的业务规则,从而实现Use Case的目标
Presenter,Controllers
- 将Use Case和Entity中的数据转换成格式最方便的数据
- 外部系统,如数据库或网页能够方便的使用这些数据
- 完全包含GUI的MVC架构
External Interfaces,UI,DB
- 所有的细节所在
- 如数据库细节,Web框架细节,等等
MVC、MCP与MVVM的关系
MVC—>MVP
MVP从更早的MVC演变过来,与MVC有一定的相似性,MVP的Presenter是框架的控制者,承担了大量的逻辑操作,而MVC的Controller更多时候承担一种转发的作用。因此在App中引入MVP的原因,是为了将此前在Activity中包含的大量逻辑操作放到控制层中,避免Activity的臃肿。
两种模式的主要区别:
- (最主要区别)View与Model并不直接交互,而是通过与Presenter交互来与Model间接交互。而在MVC中View可以与Model直接交互。
- 通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑。而Controller是基于行为的,并且可以被多个View共享,Controller可以负责决定显示哪个View
- Presenter与View的交互是通过接口来进行的,更有利于添加单元测试。
因此我们可以发现MVP的优点如下:
- 模型与视图完全分离,我们可以修改视图而不影响模型
- 可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部
- 我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁
- 如果我们把逻辑放到Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)。
MVVM
MVVM可以算是MVP的升级版,其中VM是ViewModel的缩写,ViewModel可以理解成是View的数据模型和Presenter的合体,ViewModel和View之间的监护通过Data Binding完成,而Data Binding可以实现双向的交互,这就使得视图和控制层之间的耦合程度进一步降低,关注点分离更为彻底,同时减轻了Activity的压力。
MVC,MVP还是MVVM?
那么,哪一个才是最好的呢?哪一个比其他的更优秀呢?我能只选择一个吗?
答案是,NO。
这些模式的动机都是一样的。那就是如何避免复杂混乱的代码,让执行单元测试变得容易,创造高质量应用程序。就这样。
当然,远不止这三种架构模式。而且任何一种模式都不可能是银弹,他们只是架构模式之一,不是解决问题的唯一途径。这些只是方法、手段而不是目的、目标。
利与弊
OK,让我们回到MVP架构上。刚刚我们了解了什么是MVP,讨论了MVP以及其它热门架构,并且介绍了MVC,MVP和MVVM三者间的不同。这是关于MVP架构利与弊的总结。
利
- 可测试(TDD)
- 可维护(代码复用)
- 容易Review
- 信息屏蔽
弊 - 冗余的,尤其是小型App开发
- (有可能)额外的学习曲线
- 开始编写代码之前需要时间成本(但是我敢打赌,设计架构是所有项目开发所必须的)
基于AOP的框架设计
** AOP(Aspect-Oriented Programming,面向切面编程)**
诞生于上个世纪90年代,是对OOP(Object-Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关代码被称为横切(Cross-Cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将哪些影响了多个类的公共行为封装到一个可重用模块,并将其命名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
AOP在Android中的使用
AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。在Android App中,哪些是我们需要的横切关注点?个人认为主要包括一下几个方面:Http,SharedPreferences,Json,Xml,File,Device,System,Log,格式转换等。Android App的需求差别很大,不同的需求横切关注点必然是不一样的。一般的App工程中应该有一个Util Package来存放相关的切面操作,在项目多了之后可以将其中使用较多的Util封装为一个Jar包供工程调用。
在使用MVP和AOP对App进行纵向和横向的切割之后,能够使得App整个的结构更清晰合理,避免局部的代码臃肿,方便开发测试以及后续的维护。