跳转至

UML 状态图:知识讲解与软件设计师考点

状态图描述同一个对象或系统,在生命周期中有哪些状态,以及事件如何引起状态转换。 例如,一个订单从“待付款”变成“待发货”,触发这次变化的是“支付成功”事件。

学习时先抓住一句话:在什么状态下,发生什么事件,满足什么条件,就执行什么操作、进入什么状态。

本文延续软件设计师的备考方向,重点是概念辨认、读图、执行顺序和补图。练习均为自编题,不对应某年真题,不据此推断固定考题数量或分值。

1. 先分清状态、事件和操作

概念 回答的问题 订单例子
状态 State 对象现在处于什么情况? 待付款、待发货、运输中
事件 Event 发生了什么事? 支付成功、商品发出、客户确认收货
转换 Transition 对象从哪里变到哪里? 待付款 → 待发货
守卫条件 Guard 这次转换是否被允许? 实付金额等于应付金额
转换效果 Effect 转换时要执行什么行为? 记录付款信息

“待付款”是状态,“支付成功”是事件,“记录付款信息”是操作。状态名不要写成一串流程步骤,也不要把条件当成事件。

状态既可以是等待,例如“等待输入”,也可以表示正在执行行为,例如“正在下载”。所以“状态必须静止不动”也是错误理解。

2. 用一个订单读懂状态图

下面简化为支付、发货、收货和取消几个环节。

stateDiagram-v2
    direction TB
    [*] --> Unpaid
    state "待付款" as Unpaid
    state "待发货" as Paid
    state "运输中" as Shipping
    state "已完成" as Completed
    state "已取消" as Cancelled

    Unpaid --> Paid: 支付成功(amount) [amount == 应付金额] / 记录付款
    Unpaid --> Cancelled: 取消订单 / 记录取消原因
    Unpaid --> Cancelled: after(30min) / 标记超时
    Paid --> Shipping: 商品发出 / 保存运单号
    Shipping --> Completed: 确认收货 / 记录完成时间
    Completed --> [*]
    Cancelled --> [*]

可以按一个具体实例来读:

  1. 一个订单进入“待付款”。
  2. 收到 支付成功(amount) 事件,并且金额符合要求,执行“记录付款”,进入“待发货”。
  3. 收到“商品发出”事件,保存运单号,进入“运输中”。
  4. 收到“确认收货”事件,记录完成时间,进入“已完成”,随后该状态机执行完成。

取消和超时的箭头都从“待付款”出发,所以不能根据这张图推断订单进入“运输中”后仍能直接取消。箭头的源状态也是转换条件的一部分。

图中的“已完成”“已取消”是带名称的业务状态,末尾的靶心形符号是 UML 的终态。状态机执行完成不代表必须删除订单对象或数据库记录。

这张图没有表达什么

它没有规定前端、支付服务、订单服务之间如何调用;那属于顺序图擅长表达的对象交互。它也没有把“校验支付数据、写库、发通知”等处理步骤全部展开;这些步骤可以再用活动图描述。

3. 箭头上的文字怎么读

行为状态机的转换标签常写为:

事件(参数) [守卫条件] / 转换效果

以这条转换为例:

待付款 ── 支付成功(amount) [amount == 应付金额] / 记录付款 ──→ 待发货
部分 本例 含义
源状态 待付款 当前状态需要允许这条转换
触发事件 支付成功(amount) 状态机处理到相应事件,参数可用于条件和操作
守卫条件 [amount == 应付金额] 条件为真,才可能启用这条转换
转换效果 / 记录付款 真正执行转换时才运行
目标状态 待发货 转换后进入的状态

标签中的事件、条件、效果可以按需要省略,但省略事件有特定语义,见完成转换。

条件为真,不等于马上跳转

支付成功 [金额正确] 同时要求匹配的事件和成立的条件。金额后来变得正确,不会仅因为条件变真就自动重新触发之前那次支付事件。

对没有其他可用转换、没有延期处理等额外规则的简单模型,某次事件到来时守卫为假,该转换就不执行;也不会自动执行斜杠后的操作。

如果需求就是“某条件从假变真时产生反应”,应考虑相应的变化事件,而不是把普通守卫条件当成持续监听器。

事件与条件分别怎么看

事件类型 例子 理解方式
调用事件 submit(order) 发生了相应操作调用
信号事件 paymentSucceeded 收到相应信号,适合表达异步通知
时间事件 after(30min) 相对时间到达;也可表达指定时刻的时间事件
变化事件 when(temperature > 80) 条件从假变真引发事件

在订单例子中,after(30min) 表示相对进入待付款状态的超时事件。它从“待付款”发出,不表示对象此后处于任何状态时都要无条件取消。

同一源状态上如果多条冲突转换被同一个事件启用,而且守卫条件重叠,不能按图上左右位置或文字顺序认定优先选择某一条。建模时应尽量把业务条件写清楚;若题目另给优先级或层次规则,则按题设分析。

4. 状态内部的 entry、do、exit

状态框可以写内部行为:

1
2
3
4
5
等待输入
----------------------
entry / 显示输入窗口
do / 等待并处理用户输入
exit / 关闭输入窗口
写法 何时执行 注意点
entry / 行为 进入状态时 再次进入时会再次执行
do / 行为 进入状态并完成 entry 后启动 可以持续一段时间,也可以提前完成;不是自动无限循环
exit / 行为 离开状态时 与转换箭头上的效果不同

对于两个不涉及复合层次的普通状态,执行一条外部转换时,可以记住:

退出源状态 → 执行源状态 exit → 执行转换效果 → 执行目标状态 entry → 启动目标状态 do

退出源状态时,尚在执行的 do 行为会被中止;上面的顺序不是要求把原 do 完整做完后才能处理所有事件。

例如,A 有 exit / 保存草稿,A 到 B 的箭头上写 提交 / 校验数据,B 有 entry / 显示结果,则相应顺序是:

保存草稿 → 校验数据 → 显示结果

entry、do、exit 是状态内部行为的特殊标签,不是三个普通的触发事件名称。

5. 自转换与内部转换:最值得辨析的区别

两者都可能表现为“最后仍处于同一个状态”,但执行过程不同。

stateDiagram-v2
    [*] --> Waiting
    state "等待输入" as Waiting
    Waiting: entry / 显示输入窗口
    Waiting: do / 等待并处理用户输入
    Waiting: exit / 关闭输入窗口
    Waiting: 查看帮助 / 显示帮助信息
    Waiting --> Waiting: 重置 / 清空内容

这里用状态框内的文字展示 UML 内部行为与内部转换的写法;Mermaid 负责绘图,具体语义按以下说明理解。

外部自转换

重置 / 清空内容 这条箭头从“等待输入”出发,又回到“等待输入”。本例把它定义为**外部自转换**:

1
2
3
4
5
6
退出等待输入(中止原 do)
→ 关闭输入窗口
→ 清空内容
→ 重新进入等待输入
→ 显示输入窗口
→ 重新启动 do

所以“源状态和目标状态一样,就不会执行 exit、entry”是错误的。

内部转换

状态框中的 查看帮助 / 显示帮助信息 是内部转换。它处理事件、执行效果,但**不退出、不重新进入这个状态**:

收到查看帮助事件 → 显示帮助信息

它不会因为这次内部转换而执行“关闭输入窗口”“显示输入窗口”,也不会因为该转换而重新启动原 do。

对比项 本例的外部自转换 内部转换
最后是否仍处于原状态 是 是
是否退出再进入 是 否
是否执行 exit、entry 是 否
是否重启 do 外部自转换重新进入后启动 不因这次转换而重启
典型表示 指回自己的外部转换箭头 状态框内部的事件/效果条目

涉及复合状态时,还存在局部转换 Local Transition 等规则;不能把“局部转换”与这里的“内部转换”直接当成同义词。

6. 没写事件的箭头:完成转换

如果一条转换从普通状态出发,没有显式触发事件,它可以是**完成转换 Completion Transition**,由源状态的完成事件隐式触发。

例如:

1
2
3
4
5
6
正在校验
  do / 检查资料
      │
      │ [资料有效] / 保存结果
      ▼
校验通过

这里不是“随时只要资料有效就跳过去”,而是:

  1. 处于“正在校验”,运行内部的检查行为。
  2. 简单状态的 entry、do 等所需行为完成,产生完成事件。
  3. 若守卫 [资料有效] 为真,执行“保存结果”,进入“校验通过”。

因此:

  • 没写事件,不代表任意事件都能触发。
  • do 完成,不代表一定离开。 还要看有没有可执行的完成转换。
  • 如果完成事件到来时守卫为假,不能指望以后仅凭守卫变真自动重新触发这个完成事件。
  • 对复合状态,要进一步检查它的区域是否已经完成。

初始伪状态、选择伪状态等也有不写事件的转换,但它们不应全部被笼统称为“从普通状态发出的完成转换”。要先看箭头的来源。

7. 复合状态与并发区域

复合状态:状态里面还有状态

“履约中”可以继续分成内部状态。进入内部的“待出库”时,外层“履约中”也处于活动状态。

所以“一个对象任何时候都只能处于一个状态”并不严谨。对于简单、非并发模型,同一层互斥状态中通常只有一个被激活;引入复合状态后,外层与内层可以同时处于活动状态。

正交区域:不同维度可以同时推进

例如,订单履约同时包含仓储进度和开票进度,二者是不同维度:

stateDiagram-v2
    [*] --> Fulfilling
    state "履约中" as Fulfilling {
        [*] --> StockPending
        state "待出库" as StockPending
        state "已出库" as StockDone
        StockPending --> StockDone: 出库完成
        StockDone --> [*]
        --
        [*] --> InvoicePending
        state "待开票" as InvoicePending
        state "已开票" as InvoiceDone
        InvoicePending --> InvoiceDone: 开票完成
        InvoiceDone --> [*]
    }
    state "履约完成" as Fulfilled
    Fulfilling --> Fulfilled: / 汇总履约结果
    Fulfilled --> [*]

虚线分隔的是**正交区域**。进入“履约中”后,可以同时处于仓储区域的“待出库”和开票区域的“待开票”。这不代表订单必须由两个操作系统线程实现。

本例没有外层 do 行为,并以完成转换离开“履约中”,因此两个区域都进入终态后,才执行“汇总履约结果”并进入“履约完成”。只完成开票,不足以走这条外层完成转换。

如果另有从“履约中”出发的取消等事件转换,则要按那条转换分析,不能把“两个区域都完成”误认为所有离开方式都必须遵守的条件。

8. 初始、终态和历史符号

元素 图形/记号 含义
普通状态 圆角矩形 对象在一段时间内所处的情况,可写内部行为
转换 实线箭头 从源顶点到目标顶点的转换,可标事件、条件、效果
初始伪状态 实心圆 指明进入区域的默认起点;每个区域至多一个
终态 Final State 靶心形 表示所在区域完成;终态不能再有出边
选择伪状态 Choice 菱形 到达此处时,根据守卫条件选择后续路径
浅历史 H 圆圈内 H 恢复最近活动的直接子状态;更深层不按深历史恢复
深历史 H* 圆圈内 H* 恢复最近活动的深层状态配置
终止伪状态 Terminate 叉号 X 终止整个状态机执行;不同于仅完成一个区域

初始伪状态的出边不能带触发事件或守卫条件,可以指定初始化效果。不要照搬活动图“可有多个初始节点”的规则,说同一个状态机区域也能有多个初始伪状态。

历史节点用来处理“返回复合状态时从哪里恢复”。例如退出时处于“编辑中 → 修改正文”,浅历史恢复“编辑中”,深历史还恢复其内部的“修改正文”状态配置。首次进入、尚无历史记录时,应按模型给出的默认历史路径等规则进入,而不是猜一个以前的状态。

状态图中的终态是区域完成,不能直接套用活动图中“活动终结会终止全部分支”的语义。 顶层多个区域都完成时,才表示整个状态机完成;前面并发示例中的一个区域到达终态,不会因此立即终止另一个区域。

“初始状态”“最终状态”是教材中的常见叫法;严格区分时,初始属于伪状态,Final State 属于终态。

9. 与活动图怎么区分

对比项 状态图 活动图
核心关注 对象的状态及事件响应 一件事的动作步骤、控制流与对象流
主要节点 待付款、待发货、运输中 校验库存、生成发票、通知客户
连线重点 事件、守卫条件、转换效果 动作之间怎样继续、选择或同步
同一订单的表达 支付成功后,订单变成待发货 收到付款后,依次校验、写库、通知仓库
阅读入口 先确定“在描述谁的状态” 先确定“要完成什么事情”

两者都属于 UML 行为图,且会使用相似图形。不要仅凭圆角矩形、菱形或靶心就认定图的种类,要看节点含义和整体语义。

配套阅读:UML 活动图与软件设计师考点。

10. 软件设计师读图与补图方法

复习时可按以下能力训练,不必把它们当成每年固定出现的题型组合:

训练点 典型问题 判断依据
概念识别 哪个是状态、事件、条件或效果? 代入“当前情况/发生的事/能否转换/执行操作”
路径判断 一串事件处理后,最后在哪个状态? 从当前状态找出边,逐次检查事件与条件
执行顺序 exit、转换效果、entry 谁先执行? 普通外部转换按退出、效果、进入分析
内部与自转换 状态没变,entry 是否仍可能执行? 看是否真正退出并重新进入
完成与并发 一个 do 或一个区域完成后,能否离开复合状态? 区分普通事件转换与完成转换所需条件
根据需求补图 缺的是状态名、事件、守卫还是操作? 用需求里的“处于、收到、如果、执行”逐项对应

读图可以固定为四步:

  1. 确定对象与当前活动状态,复合图还要确定活动的内部状态。
  2. 找匹配事件的候选转换,再检查守卫,不跳过源状态限制。
  3. 确定实际转换过程,需要时写出 exit、effect、entry 及 do 的变化。
  4. 更新状态再处理下一个事件,不要始终在初始状态上读全部事件。

11. 自编练习与解析

题 1:拆解转换标签

投币(amount) [amount >= 票价] / 打印车票 中,事件、守卫和效果分别是什么?

答案与解析

事件是 投币(amount),守卫是 [amount >= 票价],效果是 打印车票。源状态还必须允许这条转换;不是任何状态收到足额投币都必然打印。

题 2:条件为真就能转换吗

订单处于待付款,出边为 支付成功 [金额正确] / 记录付款。现在金额正确,但没有处理到支付成功事件,是否仅凭这个条件就进入待发货?

答案与解析

不能。 这条转换有显式触发事件,普通守卫条件只是启用条件,不能代替事件触发。

题 3:外部转换的执行顺序

A 的 exit 输出 X,A 到 B 的转换效果输出 T,B 的 entry 输出 Y。两者都是普通简单状态,不考虑 do 行为。一次该外部转换的输出顺序是什么?

答案与解析

X → T → Y。 先执行源状态退出行为,再执行转换效果,最后执行目标状态进入行为。

题 4:自转换与内部转换

状态 S 的 entry 输出 E,exit 输出 X。S 当前已经活动,现在执行效果为输出 T 的外部自转换;如果改成内部转换,两种情况下本次处理分别输出什么?

答案与解析

外部自转换:X → T → E;内部转换:T。 本题只统计这次事件处理,初次进入 S 时已发生的 entry 不重复算入。内部转换不会退出并重新进入 S。

题 5:读订单路径

按本文订单图,依次处理金额正确的“支付成功”“商品发出”“取消订单”。最后一次事件没有延期处理、没有图外其他转换。此时订单处于哪里?

答案与解析

运输中。 前两个事件依次使订单进入待发货、运输中;图中的取消箭头只从待付款出发,不能拿来处理运输中的订单。

题 6:并发区域的完成

在本文“履约中”示例里,开票区域已进入终态,仓储区域仍在待出库。没有取消等其他离开转换。是否已经可以沿外层完成转换进入履约完成?

答案与解析

不可以。 本例外层完成转换要等两个区域都完成。开票区域的终态只表示该区域完成,不会强行结束仓储区域。

参考资料

资料用于核对 UML 语义,订单业务和练习为教学示例。查阅日期:2026-09-28。

评论