一文了解MVC、MVP、MVVM、MVI架构
一文了解MVC、MVP、MVVM、MVI架构
在Android开发中,选择合适的架构模式对于提高开发效率和代码质量至关重要。本文将深入解析MVC、MVP、MVVM和MVI这四种主流架构模式,帮助开发者理解它们之间的区别和适用场景。
MVC
MVC(Model-View-Controller)架构如下图所示:
从图中可以看出,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层其实是一起的。如下图所示:
总结一下,MVC在Android上的问题主要有:
- Activity同时负责View与Controller层的工作,违背了单一职责原则
- Model层与View层存在耦合,存在互相依赖,违背了最小知识原则
MVP
MVP(Model-View-Presenter)的架构如下图所示:
从图中可以看到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(Model-View-ViewModel)架构如下图所示:
从图中可以看到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
如上图所示,MVI(Model-View-Intent)架构由如下组成。
- 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的数据单向流动。其数据流动过程如图所示:
我们一般使用ViewModel作为UI State的容器,因此响应用户输入更新UI State主要分为以下几步:
- ViewModel会存储并公开UI State。UI State是经过ViewModel转换的应用数据。
- UI层会向ViewModel发送用户事件通知。
- ViewModel会处理用户操作并更新UI State。
- 更新后的状态将反馈给UI以进行呈现。
- 系统会对导致状态更改的所有事件重复上述操作。