浅谈Android MVC、MVP、MVVM

时间:2022-09-20 21:15:43

1 架构设计的目的

通过设计使程序模块化,做到模块内部的高聚合和模块之间的低耦合。这样做的好处是使得程序在开发的过程中,开发人员只需要专注于一点,提高程序开发的效率,并且更容易进行后续的测试以及定位问题。但设计不能违背目的,对于不同量级的工程,具体架构的实现方式必然是不同的,切忌犯为了设计而设计,为了架构而架构的毛病。当然,z在架构设计的道路上,会对自身的技术越钻越优。

2 MVC 设计架构

浅谈Android MVC、MVP、MVVM

在Android中提现为:

  • 视图层(View)
    一般采用XML文件进行界面的描述,这些XML可以理解为AndroidApp的View

  • 控制层(Controller)
    Android的控制层的重任通常落在了众多的Activity(或者Fragment)的肩上。这句话也就暗含了不要在Activity,
    要通过Activity交割Model业务逻辑层处理,这样做的另外一个原因是Android中的Actiivity的响应时间是5s,
    如果耗时的操作放在这里,程序就很容易被回收掉。

  • 模型层(Model)
    我们针对业务模型,建立的数据结构和相关的类,就可以理解为AndroidApp的Model,Model是与View无关,
    而与业务相关的。对数据库的操作、对网络等的操作都应该在Model里面处理,当然对业务计算等操作也是必须放在的该层

常见的MVC包含这三层,也有Controller负责中间调度和数据准备,即Controller与Model结合了

缺点:在Android开发中,Activity并不是一个标准的MVC模式中的Controller,它的首要职责是加载应用的布局和初始化用户界面,并接受并处理来自用户的操作请求,进而作出响应。随着界面及其逻辑的复杂度不断提升,Activity类的职责不断增加,以致变得庞大臃肿。

3 MVP 设计架构

引入MVP之前,我们谈一下MVC -> MVP的关键因素:
在Android开发中,Activity(Fragment,Dialog,Window…)并不是一个标准的MVC模式中的Controller,它的首要职责是加载应用的布局和初始化用户界面,并接受并处理来自用户的操作请求,进而作出响应。随着界面及其逻辑的复杂度不断提升,Activity类的职责不断增加,以致变得庞大臃肿。

此时,MVP便从较为原始的MVC框架演变过来,与MVC有一定的相似性:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。

浅谈Android MVC、MVP、MVVM

在Android,MVP体现为:

  • View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity,Fragment,Dialog …)

  • Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合)

  • Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑

  • View interface:需要View实现的接口,View通过View interface与Presenter进行交互,降低耦合,View interface,也可用于单元测试,测试具体业务功能,省去大量的部署及测试的时间

与MVC的区别:
1.(最主要区别)View与Model并不直接交互
2.通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑
3.Presenter与View的交互是通过接口来进行的,有利于添加单元测试

MVP 强化:
1 .加入模板方法(Template Method)
转移逻辑操作之后可能部分较为复杂的Activity内代码量还是不少,于是需要在分层的基础上再加入模板方法(Template Method)。
具体做法是在Activity内部分层。其中最顶层为BaseActivity,不做具体显示,而是提供一些基础样式,Dialog,ActionBar在内的内容,展现给用户的Activity继承BaseActivity,重写BaseActivity预留的方法。如有必要再进行二次继承,App中Activity之间的继承次数最多不超过3次。

2 .Model内部分层
模型层(Model)中的整体代码量是最大的,一般由大量的Package组成,针对这部分需要做的就是在程序设计的过程中,做好模块的划分,进行接口隔离,在内部进行分层。

3 .强化Presenter

强化Presenter的作用,将所有逻辑操作都放在Presenter内也容易造成Presenter内的代码量过大,对于这点,有一个方法是在UI层和Presenter之间设置中介者Mediator,将例如数据校验、组装在内的轻量级逻辑操作放在Mediator中;在Presenter和Model之间使用代理Proxy;通过上述两者分担一部分Presenter的逻辑操作,但整体框架的控制权还是在Presenter手中。Mediator和Proxy不是必须的,只在Presenter负担过大时才建议使用。

MVC → MVP
当我们将Activity复杂的逻辑处理移至另外的一个类(Presenter)中时,Activity其实就是MVP模式中的View,它负责UI元素的初始化,建立UI元素与Presenter的关联(Listener之类),同时自己也会处理一些简单的逻辑(复杂的逻辑交由 Presenter处理)。

MVP的Presenter是框架的控制者,承担了大量的逻辑操作,而MVC的Controller更多时候承担一种转发的作用。因此在App中引入MVP的原因,是为了将此前在Activty中包含的大量逻辑操作放到控制层中,避免Activity的臃肿。

两种模式的主要区别:

  • (最主要区别)View与Model并不直接交互,而是通过与Presenter交互来与Model间接交互。而在MVC中View可以与Model直接交互
  • 通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑。而Controller是基于行为的,并且可以被多个View共享,Controller可以负责决定显示哪个View

  • Presenter与View的交互是通过接口来进行的,更有利于添加单元测试。

4 MVVM 设计架构

MVVM可以算是MVP的升级版,其中的VM是ViewModel的缩写,ViewModel可以理解成是View的数据模型和Presenter的合体,ViewModel和View之间的交互通过Data Binding完成,而Data Binding可以实现双向的交互,这就使得视图和控制层之间的耦合程度进一步降低,关注点分离更为彻底,同时减轻了Activity的压力。

浅谈Android MVC、MVP、MVVM

在Android中,MVVM体现为:

  • Model
    Model层就是职责数据的存储、读取网络数据、操作数据库数据以及I/O,一般会有一个ViewModel对象来调用获取这一部分的数据。

  • View
    我感觉这里的View才是真正的View,为什么这么说?View层做的仅仅和UI相关的工作,我们只在XML、Activity、Fragment写View层的代码,View层不做和业务相关的事,也就是我们的Activity不写和业务逻辑相关代码,一般Activity不写更新UI的代码,如果非得要写,那更新的UI必须和业务逻辑和数据是没有关系的,只是单纯UI逻辑来更新UI,比如:滑动时头部颜色渐变、editttext根据输入内容显示隐藏等,简单的说:View层不做任何业务逻辑、不涉及操作数据、不处理数据、UI和数据严格的分开。

  • ViewModel
    ViewModel 只做和业务逻辑和业务数据相关的事,不做任何和UI、控件相关的事,ViewModel 层不会持有任何控件的引用,更不会在ViewModel中通过UI控件的引用去做更新UI的事情。ViewModel就是专注于业务的逻辑处理,操作的也都是对数据进行操作,这些个数据源绑定在相应的控件上会自动去更改UI,开发者不需要关心更新UI的事情。

  • 总结: View层的Activity通过DataBinding生成Binding实例,把这个实例传递给ViewModel,ViewModel层通过把自身与Binding实例绑定,从而实现View中layout与ViewModel的双向绑定。mvvm的缺点数据绑定使得 Bug 很难被调试。你看到界面异常了,有可能是你 View 的代码有 Bug,也可能是 Model 的代码有问题。数据绑定使得一个位置的 Bug 被快速传递到别的位置,要定位原始出问题的地方就变得不那么容易了。

    通常情况下,数据的流向是单方面的,只能从代码流向UI,也就是单向绑定;而双向绑定的数据流向是双向的,当业务代码中的数据改变时,UI上的数据能够得到刷新;当用户通过UI交互编辑了数据时,数据的变化也能自动的更新到业务代码中的数据上。而DataBinding是一个实现数据和UI绑定的框架,是构建MVVM模式的一个关键的工具,它是支持双向绑定的。

    在实际的应用中很有可能你已经在不知不觉中将几种模式融合在一起,但是为了代码的可扩展、可测试性,
    必须做到模块的解耦,不相关的代码不要放在一起。所以,架构不必拘泥于形式,灵活运用才是王道。

写在最后

关于DataBing此篇并未做介绍,可以到Android Data Binding

作者Github
Demo Github地址