🎯 概述
本指南将引导您完成对以下系统的设 计与建模:电话呼叫控制系统使用UML状态机图。它重点介绍外呼呼叫生命周期,说明电话线路如何根据用户操作和网络事件在不同状态之间转换。
该图同时涵盖了正常路径(成功建立呼叫)以及异常路径(错误、超时、线路忙),强调系统的健壮性、异常处理以及清晰的状态转换——这些是实时通信系统中的关键原则。
🧩 UML状态机的核心概念
在深入分析图表之前,请先了解这些基础的UML概念:
| 概念 | 描述 |
|---|---|
| 状态 | 对象满足特定条件或执行操作的某种状态。 |
| 转换 | 由事件触发的从一个状态到另一个状态的变化。 |
| 事件 | 引发转换的事件(例如,挂机, 号码有效). |
| 自转换 | 从一个状态开始并结束于同一状态的转换(例如,digit(n)在……期间拨号). |
| 伪状态 | 特殊控制点,例如初始或最终这些并不是实际的状态。 |
| 复合状态 | 包含子状态的状态(例如错误带有忙音, 快速忙音, 录音消息). |
| 守卫条件 | 一个布尔表达式,必须为真才能发生转换。 |
✅ 专业提示:使用
event [guard] / actionUML 中的语法,用于记录触发器、条件和副作用。
🔄 外呼呼叫生命周期:逐步分解
1. 发起与拨号阶段
🔹 初始伪状态 → 空闲
-
系统从 初始伪状态.
-
尚未有活动;电话挂机。
🔹 空闲 → 拨号音 (挂机)
-
事件:
挂机(用户拿起听筒) -
转换:
挂机 → 拨号音 -
动作: 生成拨号音;准备接收数字输入。
📌 这是呼叫生命周期中的首次可见状态变化。
🔹 拨号音 → 拨号 (输入数字(n))
-
事件:
输入数字(n)(用户输入一个数字) -
转换:
输入数字(n) → 拨号 -
状态: 进入
拨号模式。
🔹 自转换:拨号 → 拨号 (输入数字(n))
-
事件:
输入数字(n)(输入多个数字) -
保护条件: 无(始终允许)
-
操作: 将数字追加到正在拨号的号码中。
-
目的: 允许在不离开
拨号状态的情况下持续输入数字。
💡 自转换对于处理电话号码之类的输入序列至关重要。
2. 连接逻辑与异常处理
🔹 拨号 → 连接(有效号码)
-
事件:
有效号码(完整号码已验证) -
转换:
有效号码 → 连接 -
操作: 启动与网络的呼叫建立。
🔹 拨号 → 录音消息(无效号码)
-
事件:
无效号码(例如:长度错误、前缀无效) -
转换:
无效号码 → 录音消息 -
操作: 播放预先录制的消息: “您拨打的号码目前无法使用。”
🔹 连接 → 忙音(号码占线)
-
事件:
号码忙 -
转换:
号码忙 → 忙音 -
操作:播放忙音;通知用户线路已被占用。
🔹 连接中 → 快速忙音(中继忙)
-
事件:
中继忙 -
转换:
中继忙 → 快速忙音 -
操作:播放快速忙音;表示网络拥塞。
⚠️ 注意:这些是错误状态会中断正常流程的状态。必须妥善处理。
3. 超时与警告机制
🔹 拨号 → 警告(超时)
-
事件:
超时在30秒无操作后 -
转换:
超时 → 警告 -
操作:播放警告提示音;通知用户继续操作或挂机。
🔹 警告 → 超时(超时)
-
事件:
超时10秒后再次 -
转换:
超时 → 超时 -
操作:取消呼叫尝试;返回到
空闲.
⏱️ 超时逻辑可防止无限等待,提升用户体验。
4. 通话中与断开连接
🔹 连接中 → 振铃(已路由)
-
事件:
已路由(网络成功路由呼叫) -
转换:
已路由 → 振铃 -
操作:向被叫方发送振铃信号。
🔹 振铃 → 已连接(被叫方接听)
-
事件:
被叫方接听 -
转换:
被叫方接听 → 已连接 -
操作:建立音频连接;开始通话录音(如果已启用)。
🔹 已连接 → 已断开(挂机 或 被叫方挂断)
-
断开连接的两种路径:
-
用户挂机:
挂机 → 已断开 -
对方挂断电话:
被叫电话挂断 → 已断开
-
🔄 两个转换都导向
已断开在到达最终状态.
🔹 已断开 → 最终状态
-
事件: 无(隐式或通过清理操作)
-
转换:
已断开 → 最终 -
动作: 清理资源,记录通话时长,更新统计数据。
✅ 最终状态表示通话生命周期的结束。
🎨 可视化设计原则:清晰性
为了让复杂的有限状态机更易读且易于维护:
| 原则 | 实现方式 |
|---|---|
| 核心正常路径 | 将主流程(空闲 → 拨号音 → 拨号中 → 连接中 → 铃响 → 已连接)保持为一条清晰的垂直或水平线。 |
| 异常情况向外分支 | 将错误状态(忙音、快速忙音、录音消息)作为侧分支放置。 |
| 分组相关状态 | 使用 复合状态 用于错误条件(见下文)。 |
| 明智地使用伪状态 | 初始和最终应明确标记。 |
| 避免交叉转换 | 避免箭头重叠;如需要,可使用正交区域。 |
🔧 高级建模技术
✅ 复合状态:“错误”分组
不要列出忙音, 快速忙音,以及录音消息作为独立状态,应将它们归入一个复合状态称为错误:
[错误]
├── 忙音
├── 快速忙音
└── 录音消息
-
入口动作:播放错误音调或消息。
-
出口动作:返回到
拨号音或空闲在用户响应后。
✅ 优点:减少视觉杂乱并提高可扩展性。
✅ 保护条件(可选增强功能)
添加保护条件以细化转换:
digit(n) [number.length < 15] → 拨号
有效号码 [number.isInternational] → 连接
🛠️ 保护条件可防止无效转换并支持条件逻辑。
📌 关键要点:复杂状态机的最佳实践
| 实践 | 为什么这很重要 |
|---|---|
| 建模不愉快的路径 | 真实系统会失败。设计时应考虑 无效号码, 超时, 中继忙 确保可靠性。 |
| 使用动作表达式 | 包含 / logCallAttempt() 或 / playTone() 以显示副作用。 |
| 保持事件详细且以动作为导向 | 使用 挂机, 已路由, 被叫电话已接听而不是e1, e2. |
| 明确命名状态 | 避免状态1, 状态2。使用拨号, 振铃, 已连接. |
| 记录假设 | 例如,“空闲30秒后超时”应在注释中注明。 |
💻 代码生成:PlantUML 和 Mermaid
以下是即用型代码块用于以您偏好的格式生成此图表。
✅ PlantUML 代码
@startuml
[*] –> 空闲
空闲 –> 拨号音 : 挂机
拨号音 –> 拨号 : 输入数字(n)
拨号 –> 拨号 : 输入数字(n) ‘ 自转换
拨号 –> 连接中 : 有效号码
拨号 –> 录音消息 : 无效号码
拨号 –> 警告 : 超时
警告 –> 超时 : 超时
连接 –> 铃响 : 已路由
连接 –> 忙音 : 号码忙
连接 –> 快速忙音 : 中继忙
铃响 –> 已连接 : 被叫电话接听
已连接 –> 断开 : 挂机
已连接 –> 断开 : 被叫电话挂断
断开 –> [*] : 清理
状态 “错误” 作为 ErrorState {
状态 “忙音” 作为 BusyTone
状态 “快速忙音” 作为 FastBusyTone
状态 “录音消息” 作为 RecordedMessage
}
‘ 内部操作
空闲 : 入口 / 等待摘机
拨号音 : 入口 / 播放拨号音
拨号 : 入口 / 收集数字
连接 : 入口 / 路由呼叫
铃响 : 入口 / 铃响远程电话
已连接 : 入口 / 建立通话会话
断开 : 入口 / 终止会话
@enduml
📥 如何使用: 粘贴到 PlantUML Live 或您的 IDE 插件。
✅ Mermaid 代码

stateDiagram-v2
[*] --> 空闲
空闲 --> 拨号音 : 挂机
拨号音 --> 拨号中 : 数字(n)
拨号中 --> 拨号中 : 数字(n) ' 自身转换
拨号中 --> 连接中 : 有效号码
拨号中 --> 录音消息 : 无效号码
拨号中 --> 警告 : 超时
警告 --> 超时 : 超时
连接中 --> 铃响 : 路由成功
连接中 --> 忙音 : 号码占线
连接中 --> 快速忙音 : 中继占线
铃响 --> 已连接 : 对方接听
已连接 --> 已断开 : 挂机
已连接 --> 已断开 : 对方挂断
已断开 --> [*] : 清理
state 错误 {
忙音
快速忙音
录音消息
}
连接中 --> 忙音 : 号码占线
连接中 --> 快速忙音 : 中继占线
拨号中 --> 录音消息 : 无效号码
note right of 忙音
播放标准忙音
end note
note right of 快速忙音
播放快速忙音(网络拥塞)
end note
note right of 录音消息
播放录音消息:"号码不在服务中。"
end note
note right of 超时
通话尝试在40秒后取消
end note
📥 如何使用: 粘贴到 Mermaid 实时编辑器 或支持的 Markdown 工具(VS Code、Obsidian 等)。
📚 总结与最终思考
这个 电话呼叫控制系统 状态机是一个 现实世界中的例子 展示了 UML 如何以高可靠性建模复杂、事件驱动的系统。
✅ 本图有效的关键因素:
-
清晰的 正常流程 具有逻辑清晰的流程。
-
全面的 错误处理.
-
使用了 自身转换, 复合状态,以及 守卫条件.
-
通过 分组 和 注释.
🛠️ 何时使用此模式:
-
电话系统
-
物联网设备控制
-
用户会话管理
-
工作流引擎
-
具有有限状态逻辑的嵌入式系统
📝 想要扩展此内容吗?
可考虑添加:
-
通话录音 状态(带有
startRecording,stopRecording事件) -
呼叫转接 逻辑(条件路由)
-
呼叫等待 支持(并行状态)
-
呼叫转移 作为 的子状态
已连接 -
状态历史 (浅层/深层历史)用于中断后的重新进入
📌 最终建议
始终建模成功和失败路径。
仅处理“顺利路径”的状态机是不完整的,在生产环境中容易出现错误。
将此指南作为 模板 用于建模任何实时系统,其中 状态转换, 事件,以及错误容错 重要。
✅ 准备生成、可视化或扩展了吗?
👉 复制上面的PlantUML或Mermaid代码,并将其集成到您的文档、架构图或系统设计文档中。
如果需要,告诉我您想要PDF版本, 交互式图表,或集成到更大的系统模型中(例如,包含组件图或时序图)!
📘 “最好的系统不仅正确,还能预见故障。”
— 使用UML状态机进行设计












