10.4.8 状态图
状态图描述一个对象在生命周期中如何响应事件、改变状态。它给出的是对象行为的动态视图,尤其适合反应式系统或触发式行为建模。
如果类图回答“对象有什么结构”,状态图回答“对象在运行中会经历哪些状态”。
状态图的核心结构
状态图描述状态机。它由状态、迁移、事件和活动组成。
mermaid
stateDiagram-v2
[*] --> 待支付
待支付 --> 已支付: 支付成功
待支付 --> 已取消: 超时/取消
已支付 --> 已发货: 发货
已发货 --> 已完成: 确认收货
已取消 --> [*]
已完成 --> [*]| 元素 | 含义 | 题目线索 |
|---|---|---|
| 状态 | 对象在某一阶段的稳定情况 | 待支付、已支付、已关闭 |
| 事件 | 触发状态迁移的事情 | 支付成功、超时、取消 |
| 迁移 | 从源状态到目标状态的转换 | 箭头 |
| 监护条件 | 迁移发生前必须满足的条件 | [条件] |
| 动作 | 迁移或状态内执行的操作 | 发送通知、更新库存 |
状态图的节点表示状态,不表示动作。动作可以发生在状态内部,也可以发生在迁移过程中。
迁移的完整形式
迁移可以很简单,也可以包含事件、监护条件和动作。常见写法可以理解为:
text
事件 [监护条件] / 动作例如:
text
支付请求 [余额充足] / 扣款并生成支付记录含义是:当支付请求事件发生,并且余额充足时,执行扣款动作,然后从源状态迁移到目标状态。
迁移也可以没有明确触发事件,表示满足条件或流程自然推进时发生;但不能因此认为“任意事件都会离开当前状态”。是否离开状态,要看图上有没有对应迁移和条件。
组合状态与嵌套状态
状态可以嵌套。一个大状态内部还可以有多个子状态,这类状态称为组合状态或嵌套状态。
mermaid
stateDiagram-v2
[*] --> B
state B {
[*] --> B1
B1 --> B2: e2
B2 --> B3: e3
}
B --> C1: e1
B2 --> C2: e4理解组合状态时要注意迁移的层级:
- 如果迁移从大状态
B发出,那么只要对象处在B内部任意子状态,触发对应事件都可能离开B。 - 如果迁移只从
B2发出,那么对象必须处在B2,触发事件才会沿这条迁移离开。
课程真题讲解里就用这个点考“不一定离开状态 B”:如果事件只对某个子状态有效,那么处于其他子状态时不会离开大状态。
状态图与活动图的区别
| 对比项 | 状态图 | 活动图 |
|---|---|---|
| 节点表示 | 状态 | 动作/活动 |
| 箭头表示 | 状态迁移 | 控制流或数据流 |
| 触发机制 | 事件、条件、动作 | 流程推进、分支、并发 |
| 适合对象 | 有明确生命周期的对象 | 有明确步骤的业务流程 |
| 例子 | 订单状态、设备开关、任务生命周期 | 登录流程、下单流程、审批流程 |
如果题干说“对象状态转换以及事件顺序”,应想到状态图;如果说“完成任务所需进行的活动流”,应想到活动图。
与状态模式的联系
后面设计模式会讲状态模式。状态图是建模工具,状态模式是设计模式。二者都围绕“状态变化影响行为”展开,但层次不同:
| 项目 | 状态图 | 状态模式 |
|---|---|---|
| 类型 | UML 图 | 设计模式 |
| 目标 | 描述状态与迁移 | 用类结构封装状态相关行为 |
| 输出 | 图形模型 | 可实现的面向对象设计 |
学状态图时先掌握事件、迁移、监护条件;学状态模式时再看如何把状态封装为对象。
例题
描述订单从“待支付”到“已支付”的变化,适合使用:
关于 UML 状态图,下列说法正确的是:
自查要点
- 状态图中的节点为什么不是活动?
- 迁移的“事件 [条件] / 动作”分别表示什么?
- 组合状态中,大状态迁移和子状态迁移有什么区别?
- 状态图与状态模式有什么联系和区别?