一文了解 MVC、MVP、MVVM、MVI架构

953 阅读5分钟

在 Android 开发中,我们常常听到各种架构,比如 MVC、MVP、MVVM 和 MVI。其中 MVI 被官方推荐。这篇文章将介绍各个架构之间的区别。

MVC

MVC 架构如下图所示:

image.png

从图中可以看出,MVC架构主要分为以下几部分

  • 视图层(View):对应于xml布局文件和java代码动态view部分
  • 控制层(Controller):主要负责业务逻辑,在android中由Activity承担,同时因为XML视图功能太弱,所以Activity既要负责视图的显示又要加入控制逻辑,承担的功能过多。
  • 模型层(Model):主要负责网络请求,数据库处理,I/O的操作,即页面的数据来源

可以看到 MVC 的完整数据流向是:View → Controller → Model → View。这样的数据流向有个问题,就是由于 Model 直接操作 View,导致 Model 和 View 耦合。

而在 Android 中,由于 xml 布局的功能性太弱,Activity 实际上负责了View层与Controller层两者的工作。所以在 android 的 mvc 中, Controller 和 View 层其实是一起的。如下图所示:

image.png

总结一下,MVC 在 Android 上的问题主要有:

  1. Activity同时负责View与Controller层的工作,违背了单一职责原则
  2. Model层与View层存在耦合,存在互相依赖,违背了最小知识原则

MVP

MVP的架构如下图所示:

image.png

从图中可以看到 MVP 架构主要分为如下部分:

  • View层:对应于Activity与XML,只负责显示UI,只与Presenter层交互,与Model层没有耦合
  • Presenter层: 主要负责处理业务逻辑,通过接口操作View层
  • Model层:主要负责网络请求,数据库处理等操作,这个和 MVC 架构一样

可以看到在 MVP 架构中,数据的流向是 View → Presenter → Model → Presenter → View。它与 MVC 架构最大的不同就是,就是 View 和 Model 不相互耦合,都通过 Presenter 做中转。同时 MVP 架构让 View 层,即 Activity 只展示 UI,从而解决了Activity同时负责View与Controller层的工作的问题。

但是MVP架构也有不足,它的缺点如下:

  • Presenter层通过接口与View通信,实际上持有了View的引用
  • 随着业务逻辑的增加,一个页面可能会非常复杂,这样就会造成View的接口会很庞大。

MVVM

MVVM 架构如下图所示:

image.png

从图中可以看到 MVVM 架构主要分为如下部分:

  • View 视图,负责界面的展示。
  • ViewModel 控制器,负责逻辑控制。
  • Model 模型,负责数据的加载和存储。

可以看到 ViewModel 层其实和 MVP 层的Presenter功能是一样。MVVM 和 MVP 的主要区别是,MVVM 增加了双向数据绑定的功能,即 View 和 ViewModel 的变动都会自动反应到对方。MVVM 的数据流向为 View ↔ ViewModel → Model → ViewModel ↔ View

在 Android 中,双向绑定一般由 DataBinding 实现。但是由于 DataBinding 存在的调试困难、复杂场景需要高度定制等问题,大部分开发者都会使用 LiveData、Flow 来观察数据变化,从而实现双向数据绑定。

MVVM 的缺点如下:

  • View层与ViewModel层的交互比较分散零乱
  • 当页面复杂时,需要定义很多LiveData,并且需要定义可变与不可变两种,该属性会以双倍的速度膨胀,模板代码较多且容易遗忘

MVI

image.png

如上图所示,MVI架构由如下组成。

  • Model: 与MVVM中的Model不同的是,MVI的Model主要指UI状态(State)。例如页面加载状态、控件位置等都是一种UI状态
  • View: 与其他MVX中的View一致,可能是一个Activity或者任意UI承载单元。MVI中的View通过订阅Model的变化实现界面刷新
  • Intent: 此Intent不是Activity的Intent,用户的任何操作都被包装成Intent后发送给Model层进行数据请求

MVI 架构最大的特点就是数据单向流动。即 View 层只能通过一个方法 notify(Event) 来通知更新 Model。而 Model 也只能通过一个 State 来监听。而在 MVVM 中,可能会有多个 LiveData 或者 Flow 来监听。

MVI 的缺点如下:

  • 所有的操作最终都会转换成State,所以当复杂页面的State容易膨胀
  • state是不变的,因此每当state需要更新时都要创建新对象替代老对象,这会带来一定内存开销

在 Android 中,目前推荐的架构就是 MVI 的数据单向流动。其数据流动过程如图所示:

image.png

我们一般使用ViewModel作为UI State的容器,因此响应用户输入更新UI State主要分为以下几步:

  1. ViewModel 会存储并公开UI State。UI State是经过ViewModel转换的应用数据。
  2. UI层会向ViewModel发送用户事件通知。
  3. ViewModel会处理用户操作并更新UI State。
  4. 更新后的状态将反馈给UI以进行呈现。
  5. 系统会对导致状态更改的所有事件重复上述操作。

参考