3. 活动图基础与功能分解
活动图是 SysML 中描述行为的主干图之一,它回答的核心问题是:一个功能从触发到结束,究竟经历了哪些动作、按什么顺序执行、在什么条件下分流或汇合、又传递了哪些对象。与用例图只说明"系统为参与者做什么"不同,活动图进一步把功能拆成可执行的动作序列,因此它既是需求到设计的桥梁,也是后续状态机、序列图建模的输入。本节围绕活动、动作、控制流、对象流、初始与终止节点、功能分解层级展开,并用一个简单任务流程完成建模练习。
一、活动、动作与节点
活动(Activity)表示一段完整的行为,通常对应一个功能或一个用例的实现;动作(Action)是活动内部不可再分(或暂不再分)的执行单元,是活动图的最小行为节点。在 SysML 中,动作用圆角矩形表示,活动本身则作为图的边界或通过 Activity 框体现。一个活动可以只含一个动作,也可以包含几十个动作,取决于分解粒度。
除动作外,活动图还有两类关键节点:控制节点与对象节点。控制节点包括初始节点、终止节点、判定/合并节点、分叉/汇合节点;对象节点表示动作之间传递的数据或物料,用矩形表示,可带类型标注。理解"动作产生或消耗对象、控制节点决定走向"这一分工,是读懂活动图的关键。
二、控制流与对象流
控制流(Control Flow)用带箭头的实线表示,只表达"执行顺序",不携带数据。例如"接收订单 → 校验库存 → 生成发货单"之间就是控制流。对象流(Object Flow)用带箭头的虚线表示,箭头方向即对象传递方向,箭头上可标注对象名与类型,如 order:Order。对象流回答的是"这个动作的输出给了谁"。
两者常同时出现:一个动作执行完后,既通过控制流触发下一个动作,又通过对象流把结果数据交给下一个动作。建模时的经验是——只要两个动作之间存在"数据依赖",就应补一条对象流,否则图只表达了时序,丢失了信息传递关系,后续无法据此推导接口。
三、初始节点与终止节点
初始节点(Initial Node)用实心圆表示,是活动的唯一入口,控制流从它出发。终止节点分两种:活动终止节点(Activity Final)用实心圆外套空心圆表示,表示整个活动结束,所有流都被终止;流终止节点(Flow Final)用圆圈内加叉表示,只终止当前这条流,其他流仍可继续。区分二者很重要:并发分支中若用活动终止,会提前杀掉其他分支;用流终止则只结束本分支。
[库存充足] / [库存不足])的出口;合并节点也是菱形,多个入口汇成一个出口。分叉/汇合节点用粗横线表示,用于表达并发。四、功能分解层级
活动图支持递归分解:一个动作可以再展开为一个子活动(Activity),子活动内部又有自己的动作、控制流和对象流。这样就形成"顶层活动 → 子活动 → 子子活动"的功能分解层级。顶层活动通常对应用例或系统级功能,第二层对应子系统职责,第三层对应具体操作步骤。分解的停止条件是:动作已可直接映射到某个具体实现(函数、服务、人工操作),再分就没有建模价值。
分解时要注意接口一致性:父活动中该动作的输入/输出对象,必须与子活动的输入参数/输出参数对应,否则分解后数据链断裂。这是初学者最常犯的错误——子活动画得很细,却和父活动的对象流对不上。
五、建模练习:订单发货流程
下面以一个简化的"订单发货"功能为例,演示从顶层到子活动的分解。顶层活动为"处理订单发货",包含动作:接收订单、校验库存、判定、生成发货单、通知客户、结束。其中"校验库存"再分解为子活动,内部含查询库存、比对数量、返回结果三个动作。
图中实线为控制流,虚线为对象流,绿色框为子活动。可以看到:顶层"校验库存"动作被展开为子活动后,其内部"查询库存 → 比对数量 → 返回结果"三个动作通过对象流传递 qty 与 result,而子活动的输出 stock 又回到顶层判定节点,形成完整的数据闭环。若把子活动内部的返回结果类型写成 Boolean,而顶层判定守卫条件写成 [库存充足],二者语义必须一致,否则分解就出现了接口错位。
六、建模检查要点
- 每个活动是否只有一个初始节点?终止节点是否区分了活动终止与流终止?
- 判定节点的每个出口是否都有守卫条件,且条件互斥、覆盖完整?
- 存在数据依赖的动作之间,是否补了对象流并标注了对象名与类型?
- 子活动的输入/输出参数是否与父活动中该动作的对象流一致?
- 分解是否已到"可直接实现"的粒度,避免过度细化或停留在口号式动作?