1. 用例图到底解决什么问题
UML设计系列写到这里,前面几篇分别聊了类图、对象图这些偏静态结构的图,这一篇轮到用例图。说实话,用例图经常被当成UML里最“简单”的一张图,很多同学画的时候也就拖几个椭圆、拉几根线,感觉半小时就完事了。但恰恰是这种“简单”的图,在实际项目里最容易画走样、画成摆设,最后评审的时候谁也说不清楚系统到底给谁用、做什么、边界在哪。
先把用例图的定位说清楚。用例图属于UML的行为图,它描述的是系统外部参与者与系统之间的交互关系,核心表达的是“谁用系统做什么”。注意这里的关键词是“外部”和“做什么”:用例图不关心内部怎么实现,不关心数据库表怎么设计,不关心接口怎么定义,它只回答三个问题——系统为谁服务,这些用户有哪些目标,系统用哪些功能满足这些目标。
我在实际项目里最常见的误解有两个。第一个是把用例图画成功能清单,系统里每个模块都拉出来画一个椭圆,比如“用户管理”“订单管理”“商品管理”,这种图严格来说不算用例图,因为“管理”不是一个具体的用户目标,而是一堆功能的集合。第二个误解是觉得用例图画完就完事了,后面设计类图、时序图的时候基本不看它,用例图变成了交付文档里的装饰品。这两种情况都浪费了用例图真正的价值。
用例图在需求阶段的核心作用其实是“对齐预期”。产品经理脑子里想的系统、开发脑子里想的系统、测试用例覆盖的范围、项目经理排期的边界,这几方对齐靠什么?靠的就是用例图这种所有人都能看懂的图形化语言。业务人员不需要懂UML,看到“读者”和“借书”之间的连线,能确认这是自己要的业务;开发看到参与者列表,能知道自己要给哪几类用户开发功能;测试看到用例清单,能推导出冒烟测试的主路径和扩展路径。一张图把多方视角收敛到一起,这就是用例图最值钱的地方。
适合读这篇内容的读者有两类。一类是软件工程、系统设计相关岗位的同学,需要在实际项目里用UML做设计,想把用例图画得专业、画得有指导意义;另一类是备考软考中级软件设计师的同学,用例图是下午案例分析题的常客,而且几乎每年都考,考题集中在参与者识别、用例识别、include与extend关系的判断。这篇文章会同时照顾这两类需求,既有设计方法论,也有应试套路拆解。
2. 核心要素与关系:别把用例图画成“功能清单”
2.1 参与者与用例的识别方法
先讲参与者。参与者(Actor)不是“人”,而是“角色”。这个区分非常关键。同一个自然人张三,在图书管理系统里既可以是“图书管理员”去处理借还书,也可以是“读者”去查询馆藏,如果按人来画参与者,就会画成一个人连着两套完全不同的用例,关系乱成一团。按角色来画,参与者代表的是“与系统交互时的一种身份”,这样才是清晰的。
识别参与者有一套非常实用的方法,叫“用户目标法”:问自己,有谁需要系统的帮助来完成某个目标?每个目标对应一个用例。这个方法好用的地方在于,它能帮你把粒度控制住。比如“读者”的目标是“查询图书信息”“预约借书”“续借”“查看借阅记录”,每一个都是一个具体用例;“图书管理员”的目标是“处理借书”“处理还书”“录入新书”“下架旧书”,同样逐个列出。参与者不要过分强求齐全,初期列一个候选清单,后面通过业务流程图比对,再增删调整。
识别用例的另外一个辅助工具是“业务事件法”:把业务运行过程中发生的事件列出来,每个事件往往对应一个用例。比如“读者来借书”是一个事件,对应“处理借书”;“读者还书超期”是一个事件,对应“处理还书”里的罚款分支;“库存图书丢失”是一个事件,可能会触发“图书盘点”用例。这个方法特别适合从业务描述文档、用户访谈记录里提取用例,不容易遗漏。
常见的命名规范是“动词+名词”,比如“查询图书”“提交订单”“审批请假”。不要用“图书查询管理”“订单处理系统”这种又长又含糊的命名,用例名里不应该出现“系统”“管理”这类词。管理从来不是目标,查询、提交、审批、删除才是。
还要提醒一个点:参与者不一定是人。外部系统也可以作为参与者。比如图书管理系统需要调用校园一卡通系统来验证读者身份,那个一卡通系统就是一个外部参与者。再比如电商系统要对接物流平台,物流平台就是参与者。这在画用例图时经常被忽略,但恰恰是系统边界界定的重要依据。哪些功能自己做,哪些功能委托给外部系统,在用例图上通过外部参与者就能看得很清楚。
2.2 包含、扩展与泛化:三种关系的判断逻辑
用例之间的关系是整张图里最费脑子的地方,也是软考和面试最喜欢考的地方。先看包含关系(include)。包含关系描述的是:基用例在执行过程中必然会调用另一个用例,被包含的用例是公共步骤,提取出来是为了复用。判断标准很简单:把被包含的用例删掉,基用例还能独立成立吗?如果不行,那就是包含。
举个例子,“借书”用例在执行时必须验证读者身份,验证读者身份这个步骤如果同时被“续借”“预约取书”等多个用例共用,那就把它提取成一个独立的“验证读者身份”用例,然后让这三个用例都包含它。判断的关键词是“必须”和“复用”。注意箭头的方向:包含关系箭头从基用例指向被包含用例,是一条虚线箭头,箭头上标注《include》。
再看扩展关系(extend)。扩展关系描述的是:基用例已经完整成立,但某些条件下需要插入额外的行为分支。判断标准是:把扩展用例从图里去掉,基用例依然完整、可用。扩展关系强调的是“条件触发”和“可选项”。
还是拿借书举例,“处理借书”这个用例本身是完整的:检查身份、登记借阅、修改库存、生成借阅记录,流程结束了。但如果读者借书时卡内余额不足——某些学校图书馆借书逾期未还时会冻结借书权限——就需要进入一个“处理借书异常”的扩展用例,提示读者先归还逾期图书。这个扩展用例就是可选分支,正常流程根本不经过它。扩展关系的箭头方向跟包含相反:从扩展用例指向基用例,同样是虚线箭头,标注《extend》,这一点几乎每次上课都会有人搞反。
最后是泛化关系(generalize)。泛化关系出现在参与者和参与者之间,也出现在用例和用例之间。参与者之间的泛化,典型场景是“教师”是“读者”的一种特殊类型,教师除了具备读者的全部能力外,还能“申请教学参考书”;用例之间的泛化,典型场景是“在线支付”是一个父用例,“支付宝支付”“微信支付”是它的子用例,子用例继承父用例的结构和约束,又可以补充自己的细节。泛化关系用实线空心箭头,箭头指向父级,表述的是“是一种”的关系。
2.3 关系速查与图示逻辑
把三种关系的判断标准压缩成一张速查表,画图的时候可以对照着用。
| 关系类型 | 判断标准 | 是否必选 | 箭头方向 | 关键字 |
|---|---|---|---|---|
| 包含(include) | 基用例必须执行该步骤 | 必选 | 基用例 → 被包含用例 | 《include》 |
| 扩展(extend) | 基用例独立完整,该分支按条件触发 | 可选 | 扩展用例 → 基用例 | 《extend》 |
| 泛化(generalize) | 子元素是父元素的一种特殊类型 | 可选 | 子元素 → 父元素 | 无需关键字 |
实做项目的时候,我建议先用文字把用例清单列出来,再判断关系,不要直接在画图工具上边拖边想。文字阶段就判断好每个用例是不是另一个用例的公共步骤、是不是某个用例的条件分支,画图的时候心里就有数,不容易把关系箭头画乱。
3. 实操:从零画一张图书管理系统用例图
理论讲再多,不如实实在在地走一遍。这里用“图书管理系统”这个最经典的案例,完整拆解从需求描述到用例图成图的整个过程。这个案例也是热词榜上被搜烂了的题,但很多人搜到的都是画好的成品图,没人讲清楚图是怎么一步步画出来的,我在这里把它补完整。
3.1 参与者识别:先列候选,再过滤精简
假设我们拿到的原始需求描述是这样的:图书馆面向在校师生开放借阅服务,读者可以查询馆藏、借书、还书、续借、预约;图书管理员负责图书的入库、编目、上架、下架和借还书处理;系统需要对接学校统一身份认证平台,验证读者身份。
第一步,把这段描述里所有“做动作的主体”圈出来:读者、图书管理员、统一身份认证平台。再想一想还有没有隐含的主体:图书馆馆长是不是需要查看图书流通统计报表?系统运维人员需不需要维护基础数据?如果需求范围没有明确要求,这些就先不加入,避免参与者清单失控。
最终确定三个参与者:读者、图书管理员、统一身份认证平台(外部系统)。这里有一个容易纠结的问题:图书管理员和系统管理员要不要分开?如果业务场景中图书管理员只负责图书和借还业务,不涉及用户权限分配和系统参数配置,就不需要画系统管理员。什么时候需要?当你要表达“系统只有超级管理员能改配置”这一条完整权限边界的时候,再单独画一个管理员参与者。用例图不是把系统所有角色都堆上去,而是只画与满足用户目标相关的角色。
3.2 用例识别:从业务流程里倒推用例清单
这一节是最核心的实操环节。识别用例最容易漏掉的是“支撑性用例”,大家普遍能想到查询、借书、还书,但想不到预约、续借、逾期处理、图书盘点这些衍生用例。我的做法是先把主流程写完整,再沿着主流程的每个分支点追问“如果不满足条件会怎样”,把异常分支也要转换成用例。
图书管理系统的核心流程可以还原成这么几条链路。读者侧:查询馆藏——确认图书可借——到馆借书——到期还书,这是最基础的主链路;如果图书已被借出,读者可以“预约图书”;借出的书到期之前,读者可以“续借”;如果读者存在逾期未还记录,系统冻结借书权限,借书时触发“处理借书异常”。图书管理员侧:新书到馆——验收——编目——入库上架,对应“图书入库”用例;读者还书——检查图书状态——处理逾期罚款——上架,对应“处理还书”用例;定期盘点——核对实物与系统库存,对应“图书盘点”用例。
把这些流程中的关键动作提取出来,得到用例清单初稿:查询图书、借书、还书、续借、预约图书、图书入库、图书下架、处理还书、图书盘点、处理借书异常、验证读者身份。其中“验证读者身份”明显是借书、续借、预约取书等用例的公共前置步骤,判断为被包含用例;“处理借书异常”是借书流程的条件分支,借书用例本身独立成立,判断为扩展用例。
3.3 画图与命名规范:让图自己会说话
用例图画得好不好,有两条硬指标:一是别人不看文档就能说出系统给谁用、能干什么;二是图和后续设计的类图能对上号,不会出现用例图里的功能在类图里找不到对应模块的情况。
画图时的布局有讲究。参与者画在系统边界框外面,这是UML的硬性规定,因为参与者是外部角色,不在系统内部;用例画在系统边界框里面;系统边界框是一个矩形,左上角写上系统名称,比如“图书管理系统”。参与者与用例之间用实线连接,表示通信关联;用例与用例之间根据前面判断好的关系画虚线和箭头。
布局建议:不同参与者放在系统框的左右两侧,避免线条交叉。比如读者放左侧,图书管理员放右侧,统一身份认证平台放顶部。系统框内部的用例按业务域分组摆放,借阅类的用例放左边,图书管理类的用例放右边,公共用例放中间,这样看图的业务人员能快速找到自己关心的区域。
命名规范再强调一遍:用例名必须是“动词短语”,不要用名词短语。比如“图书入库”可以,“图书入库管理”不行;“查询图书”可以,“图书查询模块”不行。系统边界框名字用系统全称,不要用缩写。参与者命名用业务角色名,不要用具体人名,也不要直接用“用户”这种过于宽泛的词。“用户”在用例图里是没有信息量的词,它无法回答系统的边界问题,尽量不用。
4. 用例图怎么推向后续设计:不止是一张“需求图”
很多初级设计师画完用例图就丢到一边,后面设计类图、包图、时序图时完全另起炉灶,这是特别可惜的事。用例图的价值不只是给需求评审用,它是后续所有UML图的设计原点。如果没有用好用例图,类图里的功能模块可能和需求对不上,包图的依赖关系也可能缺乏依据。
4.1 用例如何映射到类图与包图
从用例图推导类图,核心方法是“名词提取法”:用例描述里出现的每个业务名词,都有可能是一个类。拿“图书入库”用例来说,描述里会出现“新书”“图书管理员”“系统库存”“编目信息”这些概念,对应的候选类就是Book、User、Inventory、CatalogRecord。再结合用例之间的包含、扩展关系,可以进一步判断类之间的关系:借书用例包含验证身份,那么在实现时就需要一个身份验证服务类;借书用例扩展出处理借书异常,那么就需要一个异常处理分支对应的服务方法。
从用例图到包图,关注的是模块划分和依赖方向。每个用例往往对应服务层的一个功能单元,把功能相近的用例划为一个包,再把公共用例对应的服务放到基础包里,就能画出一个相对合理的包图。比如图书管理系统的查询图书、预约图书、续借、借书、还书可以都归到“借阅服务”包;图书入库、下架、盘点归到“馆藏管理”包;验证读者身份归到“认证服务”包。包与包之间的依赖方向应该是从业务包指向基础包,而不是反过来,这样后续做系统分层时边界才清晰。
4.2 用例图如何驱动评审与测试
从项目管理角度,用例图还有几个非常实用的场景。第一个是需求评审。评审会上拿着用例图和参与者清单,逐个人问“这个参与者的这些目标是不是都在范围内”,比拿着PRD一页页翻效率高得多,因为图把系统的边界一下子圈出来了。第二个是测试用例推导。每个用例至少对应一条主路径和若干扩展路径的测试用例,扩展用例对应异常路径。用例图画完之后,测试同学可以直接基于它写验收测试的框架,这也是用例图对敏捷团队最有价值的地方之一。
还有一个容易被忽视的用途是需求追踪。把用例图里的每个用例编号(比如UC-01查询图书、UC-02借书),在详细设计文档、代码模块、测试用例里都维护这个编号,需求变更时通过编号就能快速定位影响范围。比如“续借”业务规则变了,通过UC编号能找到对应的类、接口和测试用例,不用从零开始摸排代码。这个习惯在大型项目里非常救命,我个人强烈建议画用例图时就顺手把编号体系建好。
4.3 用例描述:比图本身更重要的一张表
用例图只提供索引,真正的细节在用例描述里。一张图里画了十几个用例,但“借书”到底要校验哪些条件、流程分几步、异常怎么处理,图上是看不出来的,这些要写在用例描述表里。一个完整的用例描述包括:用例名称、参与者、前置条件、后置条件、主事件流、备选事件流(扩展路径)、业务规则。
软件设计师的考试和实际项目都默认你会这一套。写主事件流时注意两点:一是步骤编号,让备选事件流能引用;二是粒度适中,一个步骤应该是一次有意义的业务操作,不用细化到键盘输入级别。比如第3步“系统校验读者身份,确认无逾期未还图书”可以;写成“系统连接数据库,执行SQL查询,返回结果”就过细了,那是时序图才需要考虑的层次。
5. 软考中级软件设计师:用例图真题怎么答
用例图是软考中级软件设计师下午案例题的重点,考察频率非常高。热词榜上“软考中级软件设计师用例图真题”“uml用例图”常年被一起搜索,说明备考的人都在找这块的备考思路。这里把真题的出题套路和解题思路做一个系统梳理,参加考试的同学可以直接拿这套方法去做题。
5.1 真题题型与通用答题策略
软考用例图题目通常分三问。第一问是补充用例图中的空缺,给你一张不完整的用例图,让你写出某几个位置应该填什么用例名称。第二问是识别参与者,让你列出图中的参与者。第三问是辨析关系,问你某两个用例之间是《include》还是《extend》,并说明理由。个别年份还会结合用例描述表考事件流的理解。
答题时有几个通用策略。第一,用例名称一定看动词。题目给出的用例描述里,找出“某人做什么”的动宾结构,基本就是答案。比如题干里写着“读者可以通过系统查询馆藏图书信息”,那就把“查询馆藏图书”填到对应位置。第二,参与者是外部角色,不是系统内部模块。题目里如果写“图书管理员可以对图书进行编目”,那么“图书管理员”就是参与者,不是用例。第三,判断关系时严格套用前面说的标准:基用例是否必须执行、基用例是否独立成立,这两个问题一确认,答案就出来了。
5.2 高频考点:include与extend的真题陷阱
软考特别喜欢在include和extend上设置陷阱,最常见的是两个。第一个陷阱是把“前置条件”误判成扩展关系。比如“借书”用例在执行前需要“登录系统”,有人把“登录系统”画成借书的扩展用例,这是错的。登录是执行借书必须的前置步骤,没有它借书根本无法完成,所以这应该是包含关系,不是扩展关系。区分的关键是看这个步骤是不是“必须执行”,而不是看它是不是发生在主流程之前。
第二个陷阱是把“异常处理”误判成包含关系。比如“网上预订图书”用例,如果库存不足就执行“取消预订”,有人会把它画成包含,认为取消也是一种处理路径。但“网上预订图书”这个用例本身是完整的,库存不足时走取消分支只是可选路径,所以应该是扩展关系。记住:包含是“都要做”,扩展是“看情况做”。
5.3 典型真题场景实战演练
用一道典型真题场景来走一遍完整答题流程。题目大致是:某在线购物系统提供商品浏览、加入购物车、提交订单、在线支付功能;用户提交订单时必须填写收货地址;如果支付失败,用户可以重新支付;系统对接第三方支付平台完成扣款。
第一问,识别参与者和用例。参与者有两个:用户、第三方支付平台(外部系统)。用例有:商品浏览、加入购物车、提交订单、填写收货地址、在线支付、重新支付。“填写收货地址”和“提交订单”的关系,因为提交订单必须要填地址,判断为包含关系;“重新支付”和“在线支付”的关系,在线支付本身独立成立,只有在支付失败时才触发,判断为扩展关系。
第三问如果问箭头方向,记住:包含关系箭头从“提交订单”指向“填写收货地址”;扩展关系箭头从“重新支付”指向“在线支付”。这个方向判断在选择题和案例题里都容易拿分,前提是不把《include》《extend》标注和箭头方向搞混。
这里再补充一个阅卷的给分点:答题时要写“判断理由”,理由里必须出现“必须执行”“独立完整”这类定性词,阅卷是按关键词给分的,只写“是包含关系”而不给理由,会扣分。
6. 常见错误与质量自查清单
画用例图画了这么多年,看了很多团队和个人画的图,发现有些错误几乎每隔一段时间就会出现。这一节把最常见的坑集中列出来,再给一份自查清单,配合前面的内容做一次复盘。
第一个错误是参与者过多或过少。过多的表现是把相同角色拆成好几个参与者,比如“本科读者”“硕士读者”“博士读者”各画一个,但他们对系统的使用方式完全一样,应该合并成一个“读者”;过少的表现是忽略了外部系统参与者,比如只画了“用户”而没有画“第三方支付平台”“统一认证平台”,导致系统边界不完整。
第二个错误是用例粒度混乱。一个图里既有“查询图书”这种细粒度用例,又有“图书管理”这种粗粒度用例,读者看图的时候会困惑到底系统的功能粒度在什么级别。解决方法是统一用用户目标来定义用例粒度,每个用例都对应一个完整目标,而不是对应一个动作或一个模块。目标是“预约图书”,不是“点击预约按钮”,更不是“图书管理”。
第三个错误是关系滥用。有些同学为了显得图丰富,给几乎所有用例都加了include或extend,结果图密密麻麻全是箭头,正确的关系反而被淹没。克制一点,只有当两个用例之间有明确的复用或分支关系时才加连线,拿不准就宁可不画,在用例描述表里用文字说明。
第四个错误是系统边界框画错。参与者必须画在框外,这是语义要求,但很多人把它画到框内,或者干脆不画系统框。不画边界框的用例图,看起来就是一堆椭圆和火柴人漂浮在页面上,系统边界模糊不清,对后续设计没有任何指导意义。
第五个错误是不写用例描述。图只是目录,细节全在描述表里。如果项目交付物只有一张用例图,没有配套的事件流说明,开发拿到之后还是得靠猜,用例图的价值就损失了一大半。
第六个错误是图与后续设计脱节。用例图画完之后,类图里找不到对应的功能模块,时序图的核心流程和用例主事件流对不上。用例图一旦和下游设计脱节,基本上就等于白画了,它的追踪价值完全丧失。
第七个错误是命名不规范。用例名用名词短语、参与者用“用户”、系统名用缩写,这些都会让图的阅读成本变高。UML图本来就是用来降低沟通成本的,命名不规范的图反而增加了沟通成本,得不偿失。
自查清单可以浓缩成五个问题:参与者和用例是不是全部在系统边界框的正确一侧?每个用例名是不是“动词+名词”的完整目标?包含关系是不是真的被多个用例复用?扩展关系是不是真的按条件触发、基用例独立成立?用例图是否能对应到后续类图和时序图的核心模块?任何一个问题回答“否”,这张图就需要返工。
我个人在实际操作中的体会是,用例图最大的价值不在“画”这个动作,而在“画之前”的思考。参与者的归类和用例的粒度一旦想清楚,后续的类图、包图、时序图都会顺很多;如果草草画完用例图,后面基本要付出数倍的时间去返工。花时间把用例图想明白,是UML设计里最划算的一笔投入。