UML 2.5核心图:类图、时序图、状态机图
好,咱们正式开始第二讲。在进入RTLA之前,我强烈建议先把UML的底子打扎实。你想想看,如果连类图和时序图都画不清楚,后面做模型转换时,很容易出现语义丢失的问题。我自己带团队时,就吃过这个亏——模型画得花里胡哨,结果代码生成出来全是bug。
UML 2.5版本其实已经非常成熟了。它不像早期版本那样臃肿,核心图就那几张。今天咱们重点讲三个:类图、时序图和状态机图。这三张图,基本覆盖了RTLA中80%的建模场景。
类图:系统的静态骨架
类图,说白了就是描述系统中“有什么东西”以及“它们之间什么关系”。我习惯把类图比作建筑的结构图——它不关心水管怎么走,只关心承重墙在哪。
类图的核心元素就三个:
- 类(Class):用矩形框表示,分三格——类名、属性、操作
- 接口(Interface):用《interface》构造型标注,或者用棒棒糖表示法
- 关系(Relationship):关联、聚合、组合、泛化、依赖
这里有个容易踩坑的地方。我曾经在项目中看到有人把聚合和组合混用。聚合是“整体-部分”的弱关系,比如车队和车——车离开车队还能跑。组合是强关系,比如人和心脏——心脏离开人就没了。嗯,这个区别在RTLA中特别重要,因为它直接影响代码生成时的生命周期管理。
重点:类图中的多重性(Multiplicity)
1..* 表示至少一个,0..* 表示零或多个。我建议你在画类图时,必须标注多重性。不标多重性的类图,在RTLA转换时会产生歧义。
来看一个简单的代码示例,对应一个“传感器”类:
// 类图对应的Java代码
public class Sensor {
private String sensorId;
private double readingValue;
public void collectData() {
// 采集数据逻辑
}
public boolean validateReading() {
return readingValue > 0;
}
}
类图的关系用线表示。泛化是空心三角实线,实现是空心三角虚线。关联是普通实线,聚合是空心菱形,组合是实心菱形。这些符号看着多,其实用几次就记住了。
时序图:交互的时间维度
时序图,我个人的理解是——它把类图中的对象“激活”了。类图告诉你系统有哪些模块,时序图告诉你这些模块在某个场景下怎么协作。
时序图的核心元素:
- 生命线(Lifeline):垂直虚线,代表一个对象的存在周期
- 激活条(Execution Specification):生命线上的矩形条,表示对象正在执行操作
- 消息(Message):水平箭头,分同步(实心箭头)、异步(开放箭头)、返回(虚线箭头)
- 交互片段(Combined Fragment):alt(选择)、opt(可选)、loop(循环)
我记得有一次做车载系统建模,团队里有人把同步消息画成了异步。结果代码生成后,两个线程之间出现了死锁。排查了两天才发现,原来是时序图上的箭头画错了。所以,箭头类型不是装饰,是语义。
我的习惯:画时序图时,先画主场景(happy path),再画异常场景。alt片段用来处理分支,opt片段用来处理可选步骤。loop片段要标注循环条件,不然别人看不懂。
时序图还有一个容易被忽略的点:时间约束。在RTLA中,我们经常需要标注“这个操作必须在10ms内完成”。UML 2.5支持在生命线上加时间标记,比如 {t=0}、{t<10ms}。这个在实时系统建模中非常实用。
状态机图:行为的状态流转
状态机图,说白了就是描述一个对象“一生中会经历哪些状态,以及怎么切换”。我特别喜欢用状态机图来建模控制逻辑,因为它比流程图更严谨。
状态机图的核心元素:
- 状态(State):圆角矩形,分初始状态(实心圆)、普通状态、最终状态(实心圆加外圈)
- 转移(Transition):带箭头的线,标注格式为“事件[守卫条件]/动作”
- 伪状态(Pseudo State):选择点(菱形)、历史状态(H)、进入/退出节点
这里有个关键点:状态和动作的区别。状态是“持续存在”的,动作是“瞬间发生”的。我曾经在项目中看到有人把“发送数据”画成一个状态,这是不对的。发送数据是一个动作,应该放在转移上,或者作为状态的do活动。
避坑指南:我曾经在一个航空电子项目中,把状态机的守卫条件写成了“dataReady == true”,结果因为浮点数比较精度问题,状态永远跳不过去。后来我改用“dataReady == 1”才解决。嗯,状态机里的守卫条件,尽量用枚举或整数,别用浮点。
状态机图支持嵌套状态(Composite State)。比如一个“运行”状态,内部可以再分“初始化”、“正常”、“降级”三个子状态。这种层次结构在RTLA中特别有用,可以降低模型的复杂度。
来看一个简单的状态机示例,对应一个“门禁系统”:
// 状态机对应的伪代码
state Idle {
on entry: 关闭门锁
on cardSwipe: 进入验证状态
}
state Verifying {
on entry: 读取卡片信息
on cardValid [权限通过] -> Open
on cardValid [权限拒绝] -> Idle
on timeout -> Idle
}
state Open {
on entry: 打开门锁,启动计时器
on doorClosed -> Idle
on timeout -> Idle
}
状态机图还有一个高级特性:协议状态机。它只关注接口的调用顺序,不关注内部实现。这个在RTLA中用于定义组件之间的交互协议,非常实用。
三张图的关系
最后,我总结一下这三张图在RTLA中的定位:
| 图类型 | 关注点 | RTLA中的用途 |
|---|---|---|
| 类图 | 静态结构 | 定义组件、接口、数据流 |
| 时序图 | 动态交互 | 描述场景、验证时序约束 |
| 状态机图 | 行为状态 | 建模控制逻辑、生命周期 |
你想想看,一个完整的RTLA模型,通常先用类图搭骨架,再用状态机图描述核心控制逻辑,最后用时序图验证关键场景。这三张图配合使用,基本能覆盖从架构到实现的全部建模需求。
嗯,这一讲的内容就到这里。记住,UML不是画图比赛,而是沟通工具。画得再漂亮,如果语义不准确,也是白搭。下一讲,我们会深入RTLA的核心概念,到时候你会看到这些UML图是怎么“活”起来的。
公众号:蓝海资料掘金营,微信deep3321