include 和 extend 的区别:什么时候用包含,什么时候用扩展(附反例)
一篇讲清 UML 用例图中 include 与 extend 的区别与判断规则:什么时候该用包含、什么时候该用扩展、方向怎么画、常见反例与替代画法。
很多人第一次画用例图时,最容易卡在两条关系上:include(包含) 和 extend(扩展)。它们看起来都像“一个用例连到另一个用例”,但背后的含义完全不同。
如果你现在的困惑是下面这些,往下看就能对上号:
- 这个步骤是“必须发生”的,还是“有条件才发生”的?
- 箭头到底指向谁?为什么我画出来总被说反了?
- 我把“登录”画成 extend 合不合适?把“校验输入”画成 include 对不对?
下面用一套可落地的判断规则讲清楚差别,并给你一些常见反例,避免“画得像、意思不对”。
先给结论:一句话区分 include 与 extend
- include:把“必做的公共步骤”抽出来复用。A include B 表示:执行 A 时,一定会执行 B(至少在语义上是必需的)。
- extend:把“可选/条件触发的分支”挂上去。A extend B 表示:在某些条件下,会在 B 的某个点插入 A;不触发条件时,B 仍然成立。
很多误用都来自把“复用”当成唯一动机。实际上:
- include 的核心是 必需性(mandatory) + 共用子流程(shared sub-flow)
- extend 的核心是 条件性(conditional) + 对基础用例的非侵入扩展(base still valid)
判断规则(建议你直接背下来)
你只要按顺序问三个问题,基本不会错。
规则 1:不执行 B,A 还能算“完成”吗?
- 不能完成 → 倾向 include(B 是 A 的必备子流程)
- 仍能完成 → 不要用 include,继续看规则 2
例子:
- “下单”若不“计算订单金额/校验库存”,就不能算完成 → 更像 include
- “浏览商品”即使不“加入收藏”,仍是完成的 → 不该 include
规则 2:A 是否是对 B 的“可选加料”,而不是 B 的必要步骤?
- 是可选加料/条件触发 → 倾向 extend
- 不是 → 继续看规则 3
例子:
- “使用优惠券”是对“结算”的可选加料:不用券也能结算 → extend
- “二次验证(MFA)”对“登录”是否可选,要看业务:
- 若对所有用户必需 → include(或直接作为登录的主流程步骤)
- 只对高风险登录触发 → extend(更贴近条件分支)
规则 3:你是为了“复用文字”,还是为了表达“需求逻辑”?
如果只是为了让图更短、避免重复写几步,但那些步骤并不独立,也不需要复用给多个用例,可以不拆。
- 用例图的目标是表达参与者与系统的交互目标,不是把每个 UI 操作都拆成一个用例。
- 过度拆分往往会把 include/extend 用成“抽函数”,图反而更乱。
箭头方向怎么画(最容易画反的点)
先说结论(按常见 UML 画法):
- include:箭头从“包含者”指向“被包含者”
- A —<
>—> B - 读法:A 包含 B
- A —<
- extend:箭头从“扩展用例”指向“被扩展(基础)用例”
- A —<
>—> B - 读法:A 扩展 B
- A —<
你可以用一句话记:
- include:A “用到了” B,所以指向被用到的 B
- extend:A “挂到” B 上,所以指向被挂的 B(B 是基础)
什么时候更适合用 include
下面这些场景,用 include 通常比较自然:
1) 多个用例都必须做同一段子流程
例:
- “下单”与“修改订单”都必须“校验库存”
- “注册”与“找回密码”都必须“发送验证码”
注意:必须 是关键。
2) 你想表达“基础能力被反复调用”
比如“身份校验/权限校验/格式校验”这种横切能力,如果确实是多个业务用例的必经步骤,抽成 include 能让图更清楚。
什么时候更适合用 extend
1) 只在某些条件下发生的分支
例:
- “风控校验”只在高风险订单触发(扩展“提交订单”)
- “人工审核”只在命中规则时触发(扩展“发起提现吗/开通权限”等)
2) 对基础用例的可选增值
例:
- “开具发票”扩展“支付完成”(不开发票也能完成支付)
- “加入收藏”扩展“浏览商品详情”(不收藏也能浏览)
这里的关键是:基础用例不被破坏,扩展只是加了一个可选动作。
5 个常见反例(以及更好的画法)
反例 1:把“登录”当成所有功能的 include
很多图会出现:下单 include 登录、发表评论 include 登录、查看订单 include 登录……
问题:
- “登录”更像一个前置条件或参与者状态,而不是每个业务目标都必须“调用一次登录用例”。
更常见的替代:
- 在用例说明里写前置条件:“用户已登录”
- 或者单独画一个“认证/会话管理”相关的用例,但不要到处 include
反例 2:把“异常处理”用 include 表达
比如“支付失败”被画成结算 include 支付失败。
问题:
- include 表达的是“必发生的子流程”,异常显然不是。
更好的画法:
- 用 extend 表达失败分支(在某条件下扩展基础流程)
- 或在用例说明里把异常流写出来
反例 3:把“输入校验”用 extend 表达
例如“校验手机号” extend “注册”。
问题:
- 大多数情况下校验是注册的必需步骤,不应是可选扩展。
更好的画法:
- 直接把校验作为注册主流程的一部分
- 或者多个用例共享且必需时,用 include 抽成子用例
反例 4:extend 被用成“继承/泛化”的替代
有些人会用 extend 表达“管理员功能包含普通用户功能”。
问题:
- 这是**角色/用例泛化(generalization)**更合适,extend 不是继承。
更好的画法:
- 对参与者用泛化:管理员 → 普通用户
- 对用例也可用泛化表达“更具体的用例”
反例 5:为了复用一句话,把所有小步骤都拆成 include
比如“点击按钮”“填写表单”“保存”都拆成用例。
问题:
- 用例应当是“用户目标”,不是 UI 原子操作。
更好的画法:
- 合并成更有意义的用例(例如“提交申请”“更新资料”)
- 把 UI 步骤放到用例说明或原型里
快速自检清单(画完 30 秒检查)
画完后,你可以用这份清单快速扫一遍:
- include 目标是否真的是“必发生”?(不做就无法完成基础用例)
- extend 是否真的是“可选/条件触发”?(不触发也不影响基础用例成立)
- 箭头方向是否一致:include 指向被包含;extend 指向基础用例
- 是否出现“把登录到处 include”“把异常用 include”的常见坑
需要一个可直接套用的模板?
如果你想把你的业务需求(参与者、目标、前置条件、可选分支)快速整理成一张用例图,可以用这个页面把信息填进去,然后导出图再微调:
如果你已经有一段需求描述(比如 PRD 里的流程、或一段“用户要做什么”的文字),也可以先把描述整理成要点,再用同一个入口生成一个初稿作为参考: