下文仅代表个人理解,可能会有偏差或错误,欢迎评论或私信讨论。
MVC
从软件架构模型角度
MVC 是比较“古老”的架构模型,后面的 MV* 都是基于它进行拓展。MVC 出现的意义是为了提高程序的可维护性与拓展性。在 View 层与 Model 层中添加了 Controller 层作为中转层。
从实现角度
在 Android 中关于 MVC 的实现比较简单粗暴,View 层就是 xml 布局文件,Controller 层就是 Activity/Fragment。但由于 xml 布局文件功能性比较差,与 UI 有关的操作主要靠 Activity/Fragment。所以, Activity/Fragment 同时承载了 View 层与 Controller 层的任务。
优缺点
- 优点:
- 通过分层思想划分不同职责,提高了程序的拓展性与可维护性
- 缺点:
- 在 Android 中由于 xml 文件功能性太低,导致 Activity/Fragment 承载了 View 与 Controller 职责,导致其复杂度太高,降低了程序可维护性。
- 三层间是互相持有,耦合度太高。
MVP
从软件架构模型角度
MVP 是从 MVC 派生出来的。Presenter 层相较于 MVC 的 Controller 层除了中转外,还承载了数据处理任务(将从 Model 层中获取的数据处理成 View 层需要的格式)。
从实现角度
在 Android 中 MVP 模型是通过接口实现的,通过定义 View 层与 Presenter 层接口,提高程序拓展性。将页面逻辑处理至 Presenter 层,降低了 Activity/Fragment 的复杂度,提高程序的可维护性。
优缺点
- 优点:
- 将页面逻辑抽离到 Presenter 层,降低了 Activity/Fragment 内部的复杂度,使其替代 xml 布局文件承担了 View 层任务。
- 通过面向接口开发,提高了代码拓展性。
- 缺点:
- View 层接口中的方法定义粒度无法保证,太细导致逻辑分散,出现"改不全"问题,太粗导致代码维护性退化。
- View 层接口仅支持单一实现,例如 Activity 和 Fragment 需要单独实现,导致无法实现跨页面通信。
- View 层与 Presenter 层相互持有,增加了耦合度,同时由于 Presenter 层持有 View 层(Activity/Fragment) 也会存在内存泄露的风险。
- Presenter 层生命周期与 Activity 一致,无法处理屏幕旋转等场景。
MVVM
关于 MVVM 架构的理解分歧还是蛮大的,主要有两种:
- MVVM 指的是 DataBinding
- MVVM 指的是 View(Activity/Fragment) + ViewModel(Jetpack组件) + Model
其实这两种理解都是对的,只是站在的角度不同。
从软件架构模型角度
MVVM 的核心就是数据绑定,借助数据绑定将 View 层与 Model 层进行解耦。ViewModel 层的作用是一个数据中转站,负责暴露 Model 层数据。所以 MVVM 也是一种数据驱动模式。
从实现角度
MVVM 在 Android 中的实现可借助 Jetpack 组件库。但要注意区分 ViewModel 层并不是指 ViewModel 组件,怎么理解这句话呢?
如果按照严格的软件架构模型实现,那么这里的 ViewModel 层需要依靠 ViewMode + DataBinding 实现。但目前 DataBinding 在大多数的项目中落地情况不是很好,所以大部分项目是通过 ViewModel + LiveData 来实现。
优缺点
- 优点:
- 借助 Jetpack 组件库可以实现生命周期感应,并且 ViewModel 生命周期长于 Activity,可处理屏幕旋转等场景。
- 通过监听/绑定方式,将 View 层与 ViewModel 层进行解耦。
- 缺点:
- 通过数据驱动的方式,并且 LiveData 仅支持单一数据类型,导致在复杂页面时 LiveData 的维护成本增加。
MVI
从软件架构模型角度
关于 MVI 目前没有明确的定义。主流的解释是“基于响应式编程实现的事件(状态)驱动模式”。这里与 MVVM 的主要区别就在于,MVVM 是数据驱动,而 MVI 是事件(状态)驱动。
从实现角度
实现 MVI 模型可以通过 View + Presenter + Model 或者 View + JetPack(ViewModel + LiveData/Flow) + Model 方式都实现。关键在于 Model 层与 View 层之间的传递的状态。
怎么理解数据驱动与事件(状态)驱动呢?(以 JetPack 实现为例)
- 数据驱动:ViewModel 持有的是数据,View 通过监听数据变化触发页面逻辑。
- 事件(状态)驱动:ViewModel 持有的是页面状态,View 通过监听状态触发页面变换。
关于具体的实现,这里推荐两个示例:
- 通过 MVP 实现 MVI(这是一篇海外博客)
- 通过 Jetpack 实现 MVI (这是 Airbnb 开源的框架)
Google 推荐框架模式
目前通过官方最新架构指南中可以发现,官方推荐通过 Jetpack 来实现 MVI 模型。
- UI Layer: 用于处理页面逻辑。内部包含了 Activity/Fragment(UI Element)、ViewModel(State Holder)
- Domain Layer: 用于处理 DataLayer 获取的数据,提高代码的复用性。
- Data Layer: 用于处理业务逻辑。内部包含了数据处理(Repositories)、数据存储(Data Sources)