如何理解 ViewModel 中的Model,为什么要叫ViewModel而不是其它的名字?
这个问题其实很有意思,而且很多 Android 开发者第一次接触 Android Jetpack 的 Android ViewModel 时都会问:
为什么叫 ViewModel ?
为什么不是 ViewController / Presenter / DataHolder?
关键就在 "Model" 这个词。
一、先理解 MVC / MVVM 里的 Model
在经典架构里,比如 Model--View--ViewModel:
View
Model
ViewModel
各自含义:
| 角色 | 作用 |
|---|---|
| View | UI(Activity / Fragment / Compose UI) |
| Model | 业务数据(Repository / Entity / Database) |
| ViewModel | 给 View 准备数据的模型 |
重点:
ViewModel 是 "View 的数据模型"
所以它叫:
View + Model
而不是普通的 Model。
二、为什么叫 "View 的 Model"
举个最简单例子。
假设 UI 要显示用户信息:
User name
User age
User avatar
真实数据可能来自:
Network API
Database
Cache
这些属于 业务 Model。
但 UI 实际需要的数据可能是:
UserNameText
AvatarUrl
IsVip
IsLoading
ErrorMessage
这些数据:
不是业务模型
而是 UI 状态
于是就需要一个 View 的模型:
data class UserUiState(
val name: String,
val avatar: String,
val isLoading: Boolean
)
这就是 ViewModel 提供的数据。
三、ViewModel 的本质
可以把 Android ViewModel 理解为:
UI State Holder
或者:
View 的数据容器
它负责:
获取数据
处理逻辑
提供 UI 状态
但:
不直接操作 UI
四、为什么不叫 Controller
早期 Android 其实更像 Model--View--Controller:
Activity = Controller
问题是:
Activity 变成:
God Class
里面全是:
网络请求
数据库
UI
业务逻辑
代码会变成:
2000+ 行
于是 Google 推了 MVVM。
五、为什么不用 Presenter(MVP)
另一种架构是 Model--View--Presenter。
View
Presenter
Model
Presenter 负责:
更新 View
但 MVP 有个问题:
Presenter 持有 View
例如:
view.showLoading()
这样:
Presenter 和 View 强耦合
而 ViewModel 不知道 View 的存在。
六、ViewModel 的核心特点
ViewModel 只做一件事:
提供数据
例如:
class UserViewModel : ViewModel() {
val userName = MutableLiveData<String>()
}
View 只负责观察:
viewModel.userName.observe(this) {
textView.text = it
}
所以:
ViewModel 不控制 UI
只提供 UI 数据
七、Android 为什么特别需要 ViewModel
Android 有个大问题:
配置变化(configuration change)
例如:
旋转屏幕
切换深色模式
语言变化
Activity 会:
destroy
recreate
如果数据在 Activity:
数据丢失
重新请求网络
而 Android ViewModel 会:
跨配置变化保存数据
生命周期:
Activity 重建
ViewModel 不重建
所以它特别适合存 UI 数据。
八、一个直观理解
可以把 ViewModel 想象成:
View 的后台秘书
流程:
UI(View)
↓
ViewModel
↓
Repository
↓
Network / Database
ViewModel 把复杂数据整理好,再交给 UI。
九、为什么这个名字其实很准确
ViewModel 的含义其实是:
Model for View
也就是:
专门为 View 准备的数据模型
所以不是:
业务 Model
而是:
UI Model
十、一句话理解
最简单理解:
ViewModel = View 的数据模型
或者:
ViewModel = UI 状态管理器
💡 一个很多 Android 开发者后来才意识到的事情:
在现代 Android 架构里:
ViewModel 才是真正的 UI 逻辑层
而:
Activity / Fragment
其实只是 UI 容器
Model是表示什么意思?数据模型吗?那为什么叫Model,而不叫Data Model?
这个问题问得非常好 👍,其实涉及 软件架构里 "Model" 这个词的历史含义 。很多人第一次看到 Model--View--Controller 或 Model--View--ViewModel 时都会以为:
Model = Data Model(数据模型)
但实际上 Model 的含义比"数据"更广。
一、Model 的本意是什么
Model 在英语里的意思是:
对现实世界某个事物的抽象表示
例如:
| 现实世界 | 模型 |
|---|---|
| 用户 | User 类 |
| 订单 | Order 类 |
| 汽车 | Car 类 |
所以:
Model = 对系统数据 + 业务规则 的抽象
它通常包含:
数据
业务逻辑
状态
规则
而不只是数据。
二、为什么不叫 Data Model
如果叫 Data Model,含义就会变成:
只表示数据结构
例如:
data class User(
val name: String,
val age: Int
)
这只是:
数据结构
但真实系统里的 Model 可能还有逻辑:
class BankAccount(
var balance: Double
) {
fun withdraw(amount: Double) {
if (amount > balance) {
throw Exception("Insufficient balance")
}
balance -= amount
}
}
这里:
balance 是数据
withdraw 是业务逻辑
整个对象才是 Model。
三、MVC 里的 Model 含义
在 Model--View--Controller 里:
Model
View
Controller
含义是:
| 层 | 作用 |
|---|---|
| Model | 业务数据 + 业务规则 |
| View | UI |
| Controller | 协调逻辑 |
所以:
Model ≠ 仅仅数据
而是:
系统的业务表示
四、Android 里的 Model
在 Android 现代架构中:
View
ViewModel
Repository
DataSource
通常:
Model 层
包括:
Repository
Database
Network
Entity
Domain logic
例如:
User
UserRepository
UserDao
UserApi
这些都属于 Model 层。
五、为什么叫 ViewModel
理解了 Model 之后就容易理解 Android ViewModel。
ViewModel
其实就是:
Model for the View
也就是:
给 View 用的模型
它描述的是:
UI 状态
UI 数据
而不是:
业务数据
例如:
data class LoginUiState(
val username: String,
val password: String,
val isLoading: Boolean,
val errorMessage: String?
)
这就是:
View 的 Model
所以叫:
ViewModel
六、一个简单类比
假设你做一个电商 App。
现实世界:
商品
价格
库存
订单
系统里:
Product (Model)
Order (Model)
但 UI 页面需要的是:
ProductNameText
PriceText
IsInStock
IsLoading
于是:
ProductViewModel
专门给 UI 用。
七、一句话总结
最准确理解:
Model = 对业务世界的抽象表示
它可能包含:
数据
规则
行为
状态
而:
Data Model
只是:
数据结构
八、一个很多人不知道的小知识
Model 这个词在 MVC 中诞生于 1970 年代,最早来自 Smalltalk GUI 系统。
后来所有架构:
- Model--View--Controller
- Model--View--Presenter
- Model--View--ViewModel
都沿用了这个词。
所以今天我们仍然用:
Model
而不是:
Data Model
分层中的Domain层又是什么意思?如何理解 这个Domain
Domain 这个词在软件架构里其实非常关键,但也最容易让人困惑。先给你一句最核心的理解:
Domain = 业务领域(Business Domain)
也就是说:
Domain 层 = 表达业务规则的那一层
不是 UI,也不是数据库,而是 系统真正的业务逻辑所在的地方。
这个概念来自 Domain-Driven Design(DDD)。
一、Domain 的字面意思
英文 Domain 原本意思是:
领域
范围
业务世界
例如:
| 系统 | Domain |
|---|---|
| 电商系统 | 商品、订单、支付 |
| 银行系统 | 账户、转账、余额 |
| 社交系统 |
分层中的Domain层又是什么意思?如何理解 这个Domain,它的单词含义有哪些,以及在分层时又表示什么?
这个问题其实触到了软件架构里的一个核心概念:Domain(领域) 。我们可以从 单词本义 → 软件架构含义 → 分层中的作用 → 具体例子 一步步理解。
一、Domain 这个单词本身是什么意思
Domain 在英语里常见含义有:
| 含义 | 解释 | 例子 |
|---|---|---|
| 领域 / 范围 | 某一类事物的范围 | science domain |
| 领域知识 | 某个专业领域的知识 | business domain |
| 统治范围 | 管辖的区域 | kingdom domain |
| 计算机领域 | 系统关注的问题空间 | problem domain |
在软件工程里,Domain 通常指:
系统所要解决的业务领域(Business Domain)
例如:
| 系统 | Domain |
|---|---|
| 电商系统 | 商品、订单、支付 |
| 银行系统 | 账户、余额、转账 |
| 社交系统 | 用户、关注、消息 |
这些就是系统的 业务世界。
二、Domain 在软件架构里的含义
在软件架构中,Domain 指的是:
业务规则 + 业务概念
也就是说:
系统真正要解决的问题
例如一个银行系统:
开户
转账
余额
利息计算
这些都属于 Domain 逻辑。
它们不是:
UI
数据库
网络请求
而是:
业务规则
三、Domain 层在分层架构中的位置
在现代架构中(例如 Android 常见架构),通常会看到三层:
Presentation
Domain
Data
关系如下:
UI / Activity / ViewModel
│
▼
Domain Layer
│
▼
Data Layer
含义:
| 层 | 作用 |
|---|---|
| Presentation | UI 展示 |
| Domain | 业务逻辑 |
| Data | 数据来源 |
四、三层分别做什么
1️⃣ Presentation(展示层)
负责:
UI
用户交互
状态展示
例如:
- Activity
- Fragment
- Compose UI
- ViewModel
2️⃣ Domain(领域层)
负责:
业务规则
业务流程
用例逻辑
常见组件:
UseCase
Interactor
Domain Model
例如:
TransferMoneyUseCase
LoginUseCase
GetUserProfileUseCase
3️⃣ Data(数据层)
负责:
网络
数据库
缓存
Repository
例如:
Retrofit API
Room DAO
Repository
五、一个具体例子(电商系统)
假设一个 下单功能。
Presentation 层
UI 调用:
viewModel.placeOrder()
Domain 层
业务逻辑:
class PlaceOrderUseCase(
private val orderRepository: OrderRepository
) {
suspend fun execute(order: Order) {
if (order.items.isEmpty()) {
throw Exception("订单不能为空")
}
orderRepository.save(order)
}
}
这里的规则:
订单不能为空
就是 Domain 规则。
Data 层
负责真正保存数据:
class OrderRepositoryImpl(
private val api: OrderApi,
private val dao: OrderDao
) : OrderRepository {
override suspend fun save(order: Order) {
api.createOrder(order)
}
}
六、为什么要有 Domain 层
如果没有 Domain 层:
Activity
↓
Repository
↓
Network
问题:
业务逻辑散落在 UI
难测试
难维护
有了 Domain 层:
UI
↓
UseCase
↓
Repository
好处:
业务逻辑集中
容易测试
结构清晰
七、Domain 层通常包含什么
在很多架构中,Domain 层会包含:
| 组件 | 作用 |
|---|---|
| Entity | 业务实体 |
| UseCase | 业务用例 |
| Repository Interface | 数据接口 |
| Domain Service | 复杂业务逻辑 |
八、Android 常见的分层结构
很多 Android 项目结构是:
presentation
├─ ui
└─ viewmodel
domain
├─ model
└─ usecase
data
├─ repository
├─ network
└─ database
依赖方向:
presentation → domain → data
九、一句话理解 Domain
最简单理解:
Domain = 业务世界
Domain 层就是:
表达业务规则的一层
十、为什么很多项目不写 Domain 层
在小项目中经常简化为:
ViewModel
↓
Repository
原因:
业务逻辑简单
但大型项目(几十万行代码)通常会加入 Domain 层。
总结
Domain 的含义:
1️⃣ 单词本义
领域 / 范围
2️⃣ 软件架构中
业务领域
3️⃣ 分层架构中
负责业务规则的一层
所以:
Domain Layer = 业务逻辑层
Entity、DTO、VO、Domain Model 到底有什么区别?还有Entity与JavaBean又有什么不同?
这几个概念在分层架构里容易混淆,但实际上它们的作用和语境是不一样的。我给你整理一个清晰的对比表和说明,让你一眼就能分清。
一、Entity(实体)
定义 :
Entity 表示 数据库或持久化层的表结构的映射对象 ,或者说是系统中可唯一标识的一类对象(有主键)。它通常包含业务数据,是 Domain 的一部分。
特点:
| 特性 | 说明 |
|---|---|
| 有唯一标识 | 通常有主键(如 id) |
| 持久化对象 | 与数据库表或存储对应 |
| 可包含业务逻辑 | 简单的规则可以放,但尽量少 |
示例(Kotlin + Room):
@Entity(tableName = "users")
data class UserEntity(
@PrimaryKey val id: Long,
val name: String,
val age: Int
)
注意:这里是数据库表映射对象。
二、DTO(Data Transfer Object,数据传输对象)
定义 :
DTO 是 用于在不同系统或层之间传输数据的对象,通常是网络 API 返回或请求的数据格式。
特点:
| 特性 | 说明 |
|---|---|
| 传输专用 | 通常和数据库结构无关,和接口约定一致 |
| 只含数据 | 一般不含业务逻辑 |
| 可序列化 | 可以转 JSON、ProtoBuf 等 |
示例(网络 API 返回):
data class UserDto(
val id: Long,
val fullName: String,
val birthYear: Int
)
注意:字段可能和数据库不完全一致,例如
fullNamevsname,birthYearvsage。
三、VO(Value Object,值对象)
定义 :
VO 表示 不可变的值对象 ,它的身份由内部值决定,而不是引用。常用于 业务逻辑层 Domain 中。
特点:
| 特性 | 说明 |
|---|---|
| 不可变 | 一般只读,不提供 setter |
| 无唯一标识 | 两个值相同就认为相等 |
| 承载业务意义 | 用于描述业务概念(金额、坐标、邮箱等) |
示例:
data class Email(val value: String) {
init {
require(value.contains("@")) { "Invalid email" }
}
}
四、Domain Model(领域模型)
定义 :
Domain Model 表示 业务领域中的核心概念及业务规则 。
可以包含 Entity + VO + 业务逻辑 ,是 Domain 层的核心。
特点:
| 特性 | 说明 |
|---|---|
| 包含业务逻辑 | 用 UseCase 操作,或者内部方法 |
| 可能组合 VO / Entity | Domain Model 不等于 Entity,但可以用 Entity 表示 |
| 纯粹面向业务 | 与 UI、数据库无关 |
示例:
data class Order(
val id: Long,
val items: List<OrderItem>,
val totalAmount: Money
) {
fun addItem(item: OrderItem): Order {
return copy(items = items + item)
}
}
这里的 Order 是 业务概念,可以用 DTO 或 Entity 数据填充,但逻辑在这里处理。
五、Entity 与 JavaBean 的区别
很多初学者把 Entity = JavaBean,其实不完全对。
| 特性 | Entity | JavaBean |
|---|---|---|
| 用途 | 持久化(数据库表) | 通用数据对象(可用于 UI、数据交换等) |
| 唯一标识 | 通常有主键 | 没有要求 |
| 业务逻辑 | 可以有部分业务规则 | 一般只存数据,没有业务逻辑 |
| 持久化注解 | 有(Room、JPA) | 无 |
| 可变性 | 可变或不可变 | 一般可变,get/set 方法 |
简单理解:
- Entity 是业务持久化的 JavaBean
- JavaBean 更宽泛,只是一种标准的 POJO 数据对象
六、总结
| 概念 | 层 | 作用 | 是否包含业务逻辑 |
|---|---|---|---|
| Entity | Data / Domain | 持久化对象 | 少量或无 |
| DTO | Data / Network | 传输对象 | 无 |
| VO | Domain | 值对象(业务概念) | 可能有验证逻辑 |
| Domain Model | Domain | 核心业务模型 | 有 |
| JavaBean | 任意 | 通用数据对象 | 一般无 |
七、简单比喻
以电商系统为例:
- DTO:接口返回 JSON → UserDto
- Entity:数据库表 → UserEntity
- VO:邮箱、价格等小业务对象 → Email, Money
- Domain Model:业务逻辑对象 → User / Order
- JavaBean:普通数据类 → 只是存数据,没有业务含义