一个UML 状态图是一种强大的可视化工具,通过展示系统在事件触发下如何在不同状态之间转换,来模拟系统的动态行为。它捕捉了对象或过程的生命周期——展示它可能处于的状态处于,是什么触发了变化,以及状态变化过程中发生哪些动作——使其非常适合理解复杂的系统,如交通灯、自动售货机、登录流程或游戏角色。通过关注状态(如“红灯”、“等待付款”或“跳跃”)、转换(由事件驱动,如“计时器到期”或“按钮按下”)以及条件(保护条件),状态图提供了清晰性,防止逻辑漏洞,并成为设计和代码的基础。无论你是初学者学习系统建模,还是开发者构建稳健的软件,掌握状态图都能让你以精确和清晰的方式思考、设计和沟通系统行为。

💡 目标:学习如何使用状态机对现实世界系统进行建模——从构思到清晰、专业的图表。
🔑 你必须首先理解的关键概念
| 概念 | 它的含义 | 为什么重要 |
|---|---|---|
| 状态 | 系统所处的一种条件或情况(例如红灯, 等待投币) |
展示任何时刻正在发生的情况 |
| 事件 | 引发变化的某种事物(例如投入硬币, 计时器到期) |
导致状态之间的转换 |
| 转换 | 从一个状态指向另一个状态的箭头 | 通过事件连接状态 |
| 初始状态 | 起点 (●) | 总是有一个 |
| 最终状态 | 过程结束 (○) | 可选——并非总是需要 |
| 守卫 [条件] | 转换发生的前提条件必须为真 | 添加逻辑(例如:钱够吗?) |
| 动作 / 入口/执行 | 进入、处于或退出某个状态时会发生什么 | 为状态添加行为 |
📌 思考:
“这个系统可以处于 X 种状态。
当 Y 发生时,它会转移到 Z.”
这就是一个状态机!
🛠 第0步——思维模式:提出这些问题
在画任何东西之前:
-
这个事物可能处于的 明显不同的状态 有哪些?
-
什么 事件(用户操作、时间、错误)会导致变化吗?
-
它能同时处于两种状态吗?(不行 → 基本状态机是互斥的。)
👉 示例:一个灯的开关要么是开或者关绝不会同时两者都有。
🧩 第一步 – 选择一个具体的对象进行建模
✅ 适合初学者的良好选择:
-
闸机(锁定/解锁)
-
交通灯(红/绿/黄)
-
自动售货机
-
登录系统
-
订单状态:
已创建 → 已支付 → 已发货 → 已送达
❌ 避免:
-
“整个在线商店” → 太大了
-
“用户体验” → 太模糊
✏️ 从简单开始。先掌握小例子。
📌 第二步 – 列出状态(使用名词或现在分词)
写下4到8个现实的状态.
使用形容词或现在分词来使其看起来像一种状态:
-
红色 -
绿色 -
黄色 -
等待硬币 -
发放物品 -
准备中 -
支付失败
✅ 提示:如果你有超过10个状态 → 将系统拆分为更小的部分。
🖌 步骤3 – 将状态绘制为圆角矩形
使用圆角矩形:
[ 红色 ]
[ 绿色 ]
[ 等待硬币 ]
✅ 工具:
draw.io / diagrams.net(最佳免费选择)
Excalidraw(手绘风格)
PlantUML(基于文本 → 易于版本控制)
Lucidchart / Miro
🔷 步骤4 – 添加初始状态(黑色圆点)
绘制一个实心黑色圆圈并用箭头指向第一个状态。
[*] --> 红色
这个
[*]表示“初始状态”——它是起点。
➡️ 步骤5 – 使用事件绘制转换
针对每个状态,问自己:
“这里会发生什么事件,让我离开这个状态?”
用以下内容标注箭头:
事件 [守卫] / 操作
🔹 从简单开始:只需
事件或事件 / 操作
常见事件:
-
投入硬币 -
计时器超时 -
支付失败 -
按钮被按下 -
行人按钮 -
超时
✅ 第6步 – 添加最终状态(可选)
使用一个带有粗边框的圆圈作为最终状态。
[已交付] --> [●]
并非所有系统都有最终状态(例如永远运行的交通灯)。
🔁 第7步 – 添加现实中的边缘情况
询问:
-
可以取消吗?→ 添加
取消→ 返回到空闲 -
时间会耗尽吗?→
超时→ 返回到等待 -
它会失败吗?→ 添加
错误→返回开始 -
它可以保持在同一状态吗?→自转换
示例:自转换(增加更多钱):
[有信用] -- 投入硬币 --> [有信用]
🚦 第8步 – 使用守卫实现智能逻辑
当同一个事件导致不同的结果,使用守卫.
示例:
如果你按下
pedButton在绿灯,但目前还没有需求 → 你进入绿灯且行人等待.
但如果需求已经设定 → 你只需忽略它。
[车辆绿灯] --> [车辆绿灯] : pedButton / set demand = true
这是一个带动作的自转换—— 不是新状态。
🎯 第9步 – 添加入口/执行/退出动作(可选但功能强大)
您可以在状态框内编写动作在状态框内:
[红色]
入口 / 打开红色
退出 / 关闭红色
执行 / 等待30秒
有助于明确行为,而不会使转换变得杂乱。
✅ 第10步 – 最终检查清单(请自问)
| ✅ 检查 | 为何重要 |
|---|---|
| 只有一个初始状态吗? | 必须从某个地方开始 |
| 所有状态都有外出箭头(最终状态除外)? | 没有死胡同 |
| 没有无法到达的状态吗? | 每个状态都应该是可到达的 |
| 转换是否用事件标记? | 清晰的因果关系 |
| 箭头不表示“前往X”——箭头仅表示方向 | 更简洁 |
| 是否包含了取消/超时/错误路径? | 真实系统会失败——请做好准备 |
| 图表是否能完整显示在屏幕上? | 清晰且易读 |
📋 快速参考:PlantUML 语法(UML 标准)
| 符号 | 含义 |
|---|---|
[*] |
初始状态 |
[*] --> 状态 |
从此状态开始 |
状态 --> 状态 |
转换 |
事件 [保护条件] / 动作 |
箭头上的标签 |
状态 "名称" |
命名状态(可选) |
状态 "X" 作为 X |
复杂名称的别名 |
状态右侧的注释 |
注释框 |
🎯 示例 1:简单的交通灯(三状态循环)
非常适合完全的初学者。
🧠 现实世界应用:
-
基本交通灯循环:红 → 绿 → 黄 → 红
✅ 状态:
-
红 -
绿 -
黄
🔄 事件:
-
计时器到期(30秒后,25秒后,5秒后)
🛠 PlantUML 代码(可复制粘贴):

@startuml
skinparam monochrome true
[*] --> 红
红 --> 绿 : after(30s)n计时器到期
绿 --> 黄 : after(25s)n计时器到期
黄 --> 红 : after(5s)n计时器到期
红 : entry / 开启红灯
绿 : entry / 开启绿灯
黄: entry / 开启黄灯
note right of 红
车辆必须停下
end note
note right of 绿
车辆可以通行
end note
note right of 黄
准备停下
end note
@enduml
✅ 如何使用:
前往 https://www.plantuml.com/plantuml,粘贴代码,然后点击“生成”。
🖼️ 输出:一个干净、带有动画效果的状态机图。
🎯 示例 2:带行人请求的逼真交通灯
该最具教育意义的版本—— 引入了守卫、自转换和复杂逻辑。
🧠 现实世界应用:
-
行人按下按钮以过马路。
-
如果有人在等待,信号灯会停留更长时间。
-
绿灯结束后,进入黄灯 → 红灯 → 允许通行 → 闪烁的禁止通行 → 回到绿灯。
📌 关键状态:
-
车辆绿灯_无需求—— 绿灯,无行人等待 -
车辆绿灯_行人等待—— 绿灯,有人按了按钮 -
车辆黄灯—— 黄灯(禁止通行) -
全红—— 安全缓冲(极短) -
行人通行—— 允许通行标志亮起 -
行人清空—— 闪烁的禁止通行(清空时间)
🧩 关键转换:
-
行人按钮—— 如果未等待 → 设置需求 -
计时器到期—— 转为黄灯(如果绿灯时间已满足) -
行人按钮—— 在黄灯/红灯期间 → 记住需求 -
计时器行走→ 转到闪烁的禁止行走 -
计时器清空→ 重置并返回绿色
🚨 注意:此版本使用守卫和自转换,展示为什么状态机功能强大.
✅ PlantUML 代码(完全可用,可直接使用):

@startuml
skinparam monochrome true
skinparam shadowing false
skinparam dpi 120
[*] --> VehicleGreen_NoDemand
state "车辆绿灯n(无行人需求)" as VG_No
state "车辆绿灯n(行人等待)" as VG_Wait
state "车辆黄灯" as VYellow
state "全红n(安全缓冲)" as AllRed
state "行人通行" as PedWalk
state "行人清空n(闪烁禁止通行)" as PedClear
VG_No --> VG_Wait : pedButton / setPedDemand = true
VG_No --> VYellow : after(35s)nor (pedDemand && minGreenTimeMet)
VG_Wait --> VYellow : after(45s)n行人等待时延长绿灯
VG_Wait --> VG_Wait : pedButton / 忽略(已等待)
VYellow --> AllRed : after(4s)
AllRed --> PedWalk : after(1s)
PedWalk --> PedClear : after(10s)n通行时间结束
PedClear --> VG_No : after(5s)n清空完成n/ resetPedDemand
note bottom of VG_No
正常运行
无行人需求
end note
note right of PedClear
行人完成过街
闪烁禁止通行标志
end note
note right of VG_Wait
行人按下按钮
绿灯最多延长10秒
end note
note right of VYellow
准备停止
车辆信号灯切换
end note
note right of PedWalk
通行标志亮起
行人可过街
end note
@enduml
💡 为什么这个版本比简单版本更好?
展示现实世界的复杂性
展示守卫 (
如果行人需求)使用自转换 (
VG_Wait --> VG_Wait)建模真实行为:绿灯可以延长!
清晰的分离车辆和行人逻辑
🎓 推荐练习题(按顺序完成)
| # | 示例 | 时间 | 学到的技能 |
|---|---|---|---|
| 1 | 灯开关(开 ↔ 关) | 5分钟 | 基本转换 |
| 2 | 闸机(锁定 ↔ 解锁) | 10分钟 | 事件,守卫 |
| 3 | 交通灯(三状态循环) | 10分钟 | 定时器,进入动作 |
| 4 | 自动售货机(等待 → 支付 → 发放) | 15分钟 | 多个事件,金钱逻辑 |
| 5 | 登录(空 → 输入 → 提交 → 成功/失败) | 15分钟 | 错误处理,最终状态 |
| 6 | 订单状态(6种状态) | 20分钟 | 现实生活中的系统建模 |
✅ 从第1–3项开始在纸上或draw.io中进行。然后使用 PlantUML 完成其余部分。
🧠 成功的最后建议
-
从小处着手 —— 不要试图一次性包含所有内容。
-
使用真实名称 —
等待硬币,而不是状态1. -
清晰地标记转换 —
按钮按下,超时,支付失败. -
先用手画出来 —— 然后数字化。
-
在脑海中测试它:“这个系统会卡住吗?” → 如果是,添加一个转换。
📌 总结:你的状态机检查清单
✅ 一个 [*] (初始状态)
✅ 圆角矩形表示状态
✅ 箭头表示转换
✅ 箭头上标注事件(30秒后, 行人按钮)
✅ 必要时添加守卫([行人请求])
✅ 自转换用于重复动作
✅ 入口/出口动作用于行为
✅ 清晰的布局,易读的字体
🎯 最后的话:你已经准备好了!
你刚刚学会了:
-
什么是状态机图
-
如何以状态和事件的思维来思考
-
如何绘制和阅读像专业人士一样
-
如何建模真实系统,例如交通灯
-
如何使用 PlantUML编写清晰、可维护的图表
🎉 你不仅仅在学习UML——你正在学习如何建模真实系统一次一个状态。
📌 下一步(你的学习路径)
-
手绘三状态交通灯——无需工具,只需纸笔。
-
尝试使用PlantUML使用上面的代码——查看其渲染效果。
-
修改:更改等待时间。添加“紧急覆盖”状态。
-
尝试使用自动售货机→ 相同逻辑,但涉及金钱。
-
绘制你自己的:一个游戏角色(行走 → 跳跃 → 攻击 → 死亡)。
💬 需要帮助吗?试试这个:“我正试图建模一个[你的系统]——你能帮我创建一个状态机吗?”
🙌 最后思考
🔄 任何会变化的事物——无论是灯、登录还是订单——都可以用状态机来建模。
你不需要是程序员也能理解它。你只需要问:“这个事物可能处于什么状态,是什么让它发生变化?”
✅ 你现在知道如何创建专业且可用的状态机图表——从初学者成长为自信的建模者。
🎉 祝你绘图愉快!
如果需要可打印的PDF版本、测验或编程挑战来检验你的技能,请告诉我。