MVC(Model-View-Controller) 和 MVVM(Model-View-ViewModel) 都是客户端/前端开发中非常经典的架构设计模式。在 Android 开发的演进历史中,MVC 是早期的主流,而 MVVM 是目前 Google 官方主推(基于 Jetpack 组件)的现代架构。
MVVM 本质上是 MVC 的一次进化。它们的核心目的都是为了**"解耦"**(将数据、业务逻辑与 UI 展示分离开来)。
以下是它们的组件对应关系和核心差异的详细拆解:
1. 组件对应关系
从宏观上看,MVC 和 MVVM 的组件对应关系如下:
|----------------------|-------------------------|----------------------------------------------------------------------------------|-----------------------------------------------------------------|
| MVC 模式 | 对应到 MVVM 模式 | 它们在架构中的职责 | Android 中的具体表现 |
| Model (模型) | ➡️ Model (模型) | 核心数据与业务逻辑。<br>负责获取、存储、处理数据。不关心 UI 如何展示。 | 数据库 (Room)、网络请求 (Retrofit)、数据仓库 (Repository) 等。 |
| View (视图) | ➡️ View (视图) | 界面的展示与用户交互。<br>负责把内容画出来,并接收用户的点击、滑动等操作。 | XML 布局文件、Activity、Fragment、Compose UI 组件。 |
| Controller (控制器) | ➡️ ViewModel (视图模型) | 中间人/大脑。<br>连接 View 和 Model,处理 View 传来的用户操作,向 Model 请求数据,并将数据加工后交给 View 显示。 | MVC 中通常是 Activity/Fragment。<br>MVVM 中是 Jetpack 的 ViewModel 类。 |
2. Controller 和 ViewModel 的本质区别 (核心考点)
虽然 Controller 演变成了 ViewModel,但它们的工作方式发生了巨大的思维范式转变。这也是 MVVM 优于 MVC 的核心原因。
在 MVC 中:Controller 是"独裁者"(命令式)
-
持有引用:Controller 直接持有 View 的引用(比如 TextView tvName)。
-
工作流:用户点击按钮 -> Controller 接收事件 -> 请求 Model 数据 -> 数据返回后,Controller 直接调用 tvName.setText("张三") 来更新 UI。
-
痛点:在 Android 中,Activity 同时充当了 View 和 Controller 的角色。随着业务增加,Activity 变得极其臃肿(俗称 Massive View Controller),且极难编写单元测试(因为逻辑和 UI 控件强绑定)。
在 MVVM 中:ViewModel 是"广播站"(响应式/观察者模式)
-
双向隔离 :ViewModel 绝对不持有任何 View(UI 控件)的引用。它根本不知道是谁在显示它的数据。
-
工作流:
-
ViewModel 内部维护一份"状态数据"(比如 val name = MutableStateFlow("张三"))。
-
View 提前**订阅(Observe)**这个状态数据。
-
用户点击按钮 -> View 通知 ViewModel 去获取数据。
-
ViewModel 拿到数据后,仅仅是把内部的 name 更新为 "李四"。
-
View 因为一直监听着 name,自动察觉到变化,UI 自己刷新了文字。
-
-
优势:UI 和逻辑彻底解耦。ViewModel 变成了纯粹的 Java/Kotlin 代码,极其容易测试;并且完美契合了 Android 的生命周期(配置更改如屏幕旋转时,ViewModel 数据不会丢失)。
3. 具体对应关系与示例(以 Android 为例)
假设我们要实现一个"输入账号密码,点击登录"的功能:
【过去:MVC 时代的写法】
-
View & Controller (混合体):LoginActivity.kt
-
包含 UI 控件:EditText, Button。
-
同时包含控制逻辑:监听 Button 点击,调用网络请求,判断成功后 Toast.show 或者跳转页面。
-
-
Model:AuthManager.kt(负责实际发起 HTTP 请求)。
痛点:LoginActivity 代码上千行,如果改了界面的某个按钮,经常容易引发空指针异常。
【现在:MVVM 时代的写法】
-
View:LoginActivity.kt 或 LoginScreen.kt (Compose)
- 只负责:把输入框的内容发给 ViewModel,观察 ViewModel 的状态(Loading 还是 Success),然后根据状态展示转圈动画或跳转页面。
-
ViewModel:LoginViewModel.kt
- 只负责 :接收传入的账号密码,调用 Repository 发起请求,然后把一个表示状态的变量(比如 UiState)改为 Loading,请求结束改为 Success。没有任何 Android 相关的 import。
-
Model:UserRepository.kt (结合 Retrofit)。
总结
-
Model 没有变:无论 MVC 还是 MVVM,底层的数据获取和存储逻辑都是相对独立的。
-
View 更纯粹了:在 MVVM 中,View 被剥夺了业务决策权,退化为一个纯粹的"状态展示机"。
-
Controller 进化成了 ViewModel :从**"主动命令 View 做事情 (Controller)",变成了 "我只管准备好数据,View 你自己看着办 (ViewModel)"。底层支撑这一变化的技术是 数据绑定(DataBinding)或响应式流(LiveData / StateFlow / Compose State)**。