4. 用例建模:参与者与用例的识别、用例图绘制、用例描述(基本流与备选流)、用例间关系(包含、扩展、泛化)

好,咱们进入用例建模这个环节。说实话,这是我在MBSE课程里最看重的一块。为什么?因为用例模型是连接用户需求和系统设计的桥梁。你想想看,如果连谁在用系统、用来干什么都说不清楚,后面的设计全是白搭。

4.1 参与者与用例的识别

先说说参与者。参与者不是指具体的人,而是指与系统交互的角色。我见过很多新手一上来就写“张三”、“李四”,这不对。参与者应该是“普通用户”、“管理员”、“外部支付系统”这类抽象角色。

识别参与者有个简单方法:问自己三个问题——

  • 谁在使用系统的主要功能?
  • 谁需要系统的支持来完成工作?
  • 谁维护和管理系统?

至于用例,说白了就是参与者想通过系统达成的一个完整目标。比如“用户登录”是一个用例,“修改密码”是另一个。注意,不是每个操作都是用例。“输入用户名”这个操作太细了,它只是“用户登录”的一部分。

我的经验:我在一个电商项目中,团队把“添加商品到购物车”和“结算”拆成了两个用例。后来发现用户真正关心的是“完成购买”,而“添加商品”只是前置步骤。最后我们合并了用例,反而更清晰。

4.2 用例图绘制

用例图其实不复杂。核心元素就三个:参与者(小人图标)、用例(椭圆)、关系(连线)。我习惯用UML标准画法,参与者放在系统边界外部,用例放在内部。

画图时注意几点:

  • 系统边界用矩形框表示,框内是系统功能,框外是外部角色
  • 参与者与用例之间用实线连接,表示“谁发起了什么”
  • 用例之间可以有包含、扩展、泛化关系

举个例子,一个简单的图书馆管理系统:

参与者:读者、管理员、外部支付系统
用例:借书、还书、查询图书、缴纳罚款、管理图书

画出来就是:读者连接借书、还书、查询图书;管理员连接管理图书;外部支付系统连接缴纳罚款。就这么简单。

避坑指南:我曾经犯过一个错误——把系统内部功能也画成用例。比如“验证用户身份”这个功能,它其实是“用户登录”用例的一部分,不应该单独作为一个用例。记住,用例是对外提供的完整服务,不是内部步骤。

4.3 用例描述:基本流与备选流

用例图只是骨架,真正的血肉在用例描述里。我一般用模板来写,包含:用例名称、参与者、前置条件、后置条件、基本流、备选流。

基本流是正常情况下的执行路径。比如“用户登录”的基本流:

  1. 用户输入用户名和密码
  2. 系统验证信息
  3. 验证通过,进入主界面

备选流是异常或分支情况。比如:

  • 备选流A:用户名不存在 → 提示错误,返回步骤1
  • 备选流B:密码错误 → 提示错误,允许重试3次
  • 备选流C:连续3次错误 → 锁定账号,通知管理员

为什么要区分基本流和备选流?说白了,基本流是“理想状态”,备选流是“现实世界”。你想想看,用户输错密码太常见了,如果不写清楚备选流,开发人员可能就只实现了“登录成功”这一条路。

我的习惯:写用例描述时,我会先写基本流,再逐条补充备选流。备选流要覆盖所有可能的异常情况,包括:输入错误、权限不足、系统超时、外部服务不可用等。

4.4 用例间关系:包含、扩展、泛化

用例之间不是孤立的。UML定义了三种关系:

关系类型 符号 含义 例子
包含(include) 虚线箭头 + <<include>> 一个用例必然包含另一个用例的行为 “借书”包含“验证读者身份”
扩展(extend) 虚线箭头 + <<extend>> 一个用例在特定条件下扩展另一个用例 “借书”在超期时扩展“计算罚款”
泛化(generalization) 实线空心箭头 子用例继承父用例的行为 “在线支付”和“现金支付”泛化“支付”

包含关系:我习惯把它理解成“必须做”。比如“借书”这个用例,不管谁来借,都必须先验证身份。所以“借书”包含“验证读者身份”。箭头从“借书”指向“验证读者身份”。

扩展关系:这是“可能做”。比如“借书”时,如果读者有超期未还的书,系统会触发“计算罚款”。但这不是每次借书都会发生,所以是扩展。箭头从“计算罚款”指向“借书”。

泛化关系:这是“是一种”。比如“在线支付”和“现金支付”都是“支付”的一种方式。子用例继承父用例的所有行为,还可以添加自己的特殊行为。

避坑指南:我曾经在一个项目中,把包含和扩展搞混了。团队花了两周时间才发现“用户注册”用例里包含了“发送验证邮件”,但有些注册场景不需要发邮件。后来改成扩展关系才解决问题。记住:包含是“每次都要”,扩展是“有时需要”。

嗯,到这里用例建模的核心内容就讲完了。总结一下:参与者是角色,用例是目标,用例图是骨架,用例描述是血肉,关系是粘合剂。你想想看,如果把这些都做扎实了,需求分析阶段基本不会出大问题。