Read this post in: de_DEen_USes_ESfr_FRhi_INid_IDjapl_PLpt_PTru_RUvizh_TW

掌握UML用例关系:«include» 和 «extend» 的力量与风险

UML2 days ago

在软件需求和系统建模领域,UML(统一建模语言)仍然是可视化系统行为的基石。在其最强大却经常被误解的功能中,包括«include» 和 «extend» 用例之间的关系。这些机制旨在减少重复管理变异性,以及增强模块化用例模型中。然而,它们的误用极为普遍——导致图表过于复杂,利益相关者困惑,以及对用户价值的关注丧失。

 

 

本文提供了一份全面、实用且有专家支持的指南用于理解、应用和避免«include»和«extend»的常见陷阱。我们将探讨它们的真实语义,进行对比分析,探讨它们为何陷入与DFD(功能分解)相同的陷阱,并提供现代最佳实践适用于2025–2026年团队——尤其是那些在敏捷、精益或混合环境中工作的团队。


🔹 核心语义:«include» 和 «extend» 的真正含义真正意味着

✅ «include»:强制重用——“始终必需”的子流程

定义:
«include» 关系表示一个必须的,始终执行被提取出来以在多个用例中复用的子流程。

📌 关键特性:

  • 始终执行:包含的用例在每次调用基础用例时都会运行。

  • 没有它,基础用例就不完整:如果没有包含的行为,基础用例就无法实现其目的。

  • 依赖方向:箭头指向从基础 → 包含.

  • 独立意义:包含的用例通常单独没有意义——只有作为更大流程的一部分时才有意义。

  • 类比:就像编程中的函数调用子程序——对主程序至关重要。

🧠 经典记忆法:

“要执行登录,你必须验证用户.”
“要执行取现,您必须验证PIN码.”

这些是不可协商的步骤没有认证您无法登录。没有验证PIN码您无法取现。

💡 何时使用:

  • 当一个常见、复杂且可复用的行为出现在两个或更多用例中。

  • 示例:

    • 用户认证

    • 记录审计日志

    • 发送通知

    • 验证输入格式

✅ 经验法则:仅当复用的行为是重要非平凡,并且出现在≥2–3用例中。


✅ «extend»:可选变体——“条件附加”

定义:
「扩展」关系定义了可选的、条件性的或变体的行为,它插入到一个特定的扩展点基础用例中。

📌 关键特性:

  • 条件执行:仅在特定条件下运行。

  • 基础用例可独立完整:正常流程无需扩展即可运行。

  • 依赖方向:箭头指向从扩展 → 基础(反向)。

  • 独立意义:扩展用例通常几乎从不单独有意义——只有在上下文中才有意义在上下文中.

  • 类比:就像一个钩子插件,或AOP(面向切面编程)建议——它在特定点添加行为。

🧠 经典记忆法:

“在执行 预订航班时,您可能想要选择首选座位.”
“在执行 使用信用卡支付时,您可能需要输入3D安全码.”

这些是可选的增强功能——并非核心流程所必需。

💡 何时使用:

  • 用于建模替代路径异常情况,或可选功能.

  • 当用例具有变体行为基于条件(例如,用户角色、系统状态、偏好)时。

  • 示例:

    • 应用折扣(扩展下单)

    • 申请退款(扩展处理付款)

    • 生成PDF收据(扩展完成交易)

✅ 经验法则:谨慎使用«扩展»——仅用于有意义的变体具有明确的扩展点.


🔍 快速对比:«包含» 与 «扩展»

方面 «包含» «扩展»
执行 总是 有时/有条件地
基础用例是否可独立完成? ❌ 否——依赖于包含的内容 ✅ 是——无需扩展即可完成
依赖方向 基础 → 包含 扩展 → 基础
箭头方向 指向被包含的用例 指向基础用例
主要目标 重用必需的、共享的步骤 处理可选/变体流程
类比 函数调用 / 子程序 钩子 / 插件 / AOP建议
具有独立意义吗? 很少 几乎从不
最适合 可重用的、复杂的、横切关注点 条件性、可选性或替代性行为

⚠️ “分解陷阱”:为什么用例图会偏离正轨

就像DFD(数据流图)会受到功能分解陷阱,用例图也容易患上同样的致命疾病过度分解.

📉 DFD功能分解陷阱(回顾):

  • 团队不断将流程拆分成越来越小的气泡。

  • 图表分解为数十个微小的低级函数。

  • 那个 原始目的——为用户提供价值——被遗忘了。

  • 最终看起来像 伪代码 或 内部算法设计,而不是用户行为。

🧨 用例“功能分解病”:

  • 每一个微小步骤都变成了一个独立的用例:

    • 输入用户名

    • 输入密码

    • 点击登录按钮

    • 验证格式

    • 显示错误信息

  • «包含»被应用 广泛地 以分解每一个操作。

  • 结果:一个 深层层级 的用例层级(A → B → C → D…),没有明确的参与者目标。

  • 图表变得 难以维护令人困惑,以及 对利益相关者毫无用处 对利益相关者。

❌ 红色警告: 如果你的用例图包含超过15到20个用例,或者如果大多数基础用例的步骤为2到4步你很可能陷入了陷阱。


🛠️ 问题原因:常见陷阱与误解

陷阱 解释 如何避免
过度使用«include» 将每个子步骤都视为可重用的用例。 仅在以下情况下使用«include»:重要可重用跨切面行为(例如:认证、日志记录)。
混淆箭头方向 将«include»箭头画反(基础 ← 包含)或«extend»箭头画正向。 记住:include = 基础 → 包含extend = 扩展 → 基础.
将«extend»用于替代流程 将替代流程建模为内部一个用例的«extend»,而不是使用文本形式的替代方案。 使用 文本替代流程 用于大多数变体。将«扩展»保留用于 真正的可选扩展.
创建包含链 A → B → C → D → E… 避免过深的链。如果需要多个包含,考虑 重构为单一可重用用例.
模糊的扩展点 在没有明确命名插入点的情况下添加«扩展»关系。 定义 明确的扩展点 (例如,“支付确认后”)在基础用例中。
图表杂乱 用例和关系过多 → 视觉干扰。 保持图表 简洁、聚焦且以参与者为中心。每个子系统使用多个图表。
利益相关者困惑 非技术利益相关者难以理解«包含/扩展»。 使用 文本场景或 用户故事地图 以提高清晰度。
设计层面的建模 建模内部架构(例如,“调用数据库”)而非用户目标。 专注于 角色价值——而非实现。
无休止的争论 团队争论“是使用include还是extend?”而不是编写用例场景。 使用实用的启发式方法优先考虑清晰性而非形式化.

✅ 2025–2026 年最佳实践:现代敏捷方法

需求工程的格局已经发生变化。敏捷、精益和以产品为导向的团队正越来越多地摆脱复杂的UML图,转而采用轻量级、以价值为导向方法。

🎯 核心原则:关注角色价值,而非内部结构

❗ 在添加任何«include»或«extend»之前,请问这个问题:
“这个关系有助于用户理解目标吗?还是仅仅在分解系统?”

✅ 推荐的现代实践:

1. 谨慎使用«include»——仅用于主要的可重用行为

  • 仅用于横切关注点出现在多个用例中。

  • 示例:

    • 验证用户

    • 发送电子邮件通知

    • 记录安全事件

    • 应用业务规则

❌ 避免:输入用户名点击提交验证电子邮件格式

2. 优先选择文本替代流程,而非「扩展」

  • 而不是:

    「扩展」:选择首选座位 → 预订航班
    
  • 使用:

    用例:预订航班
    ...
    替代流程:
      1. 用户选择「首选座位」选项。
      2. 系统显示座位图。
      3. 用户选择座位。
      4. 系统应用座位偏好。
    

✅ 为什么?文本流程具有更易阅读更高的灵活性,以及更不易被误用.

3. 保持用例图简洁且聚焦

  • 每个参与者子系统.

  • 限制为5–10 个用例每个图。

  • 使用包图上下文图以展示高层结构。

4. 问:“用户故事地图是否能更好地传达这一点?”

  • 如果你使用了10个以上的«包含»/«扩展»关系,请考虑用以下方式替代该图:

    • 一个用户故事地图

    • 一个基于场景的表格

    • 一个简单的流程图并包含关键路径

🔄 现代趋势:许多敏捷团队完全避免使用用例图或仅在高层探索时使用.

5. 仅在有意义的变体中使用 «extend»

  • 将 «extend» 保留给可选的,非核心功能,例如:

    • 很少使用

    • 依赖上下文

    • 独立的与核心目标无关

✅ 示例:
处理付款(基础)
应用 3D 安全认证(扩展)——仅在银行要求时使用

❌ 避免:
输入卡号 → 验证卡片 → 处理付款(所有步骤都应属于同一个用例)


📊 总结:«include» 和 «extend» 的黄金法则

规则 指导
1. «include» = 必需 仅用于关键且可重用在至少两个用例中出现的步骤。
2. «extend» = 可选 仅在以下情况下使用条件性、变体或罕见行为。
3. 基础用例必须完整 «extend»:基础用例可独立运行。«include»:基础用例缺少它则不完整。
4. 保持简洁 如果一个用例在«include»/«extend»之后的步骤少于4–6步,说明你过度分解了。
5. 优先考虑可读性 文字场景 > 复杂图示。
6. 避免链式结构 不要出现 A → B → C → D 的结构。应重构为一个可复用的用例。
7. 了解你的受众 利益相关者并不关心«include»箭头——他们关心的是价值.
8. 问自己:“这是用户目标还是内部步骤?” 如果它不是参与者的目标,很可能就不应包含在用例中。

🎯 最终思考:工具,而非陷阱

«include» 和 «extend» 是强大的工具——而非僵化的规则。它们的设计目的是:

  • 减少重复

  • 管理变异性

  • 提高可维护性

但就像DFD中的功能分解一样,它们一旦被过度使用,就会变成危险的武器当被过度使用时。真正的危险并非这些关系本身——而是忽视用户的目标.

🔥 记住:
用例不是技术流程。
它是一个关于用户想要实现的目标的故事——以及系统如何提供帮助。

如果不确定,问问自己:

“用户在不了解UML的情况下能否理解这一点?”
如果不能,就简化。
如果可以,你就走在正确的道路上。


📚 进一步阅读与参考

  • UML 规范(OMG)www.omg.org/spec/UML

  • 马丁·福勒 – 用例建模分析模式 & UML 精要

  • 伊瓦尔·雅各布森 – 面向对象的优势:用例的基础性工作

  • 敏捷建模(AM)作者:斯科特·W·安布勒

  • 用户故事地图作者:杰夫·帕顿 – 复杂图表的现代替代方案


✅ 一句话规则

使用«include»进行强制重用,«extend»用于可选的变体——但仅在真正增加价值时才使用。否则,保持简单。

因为最终,目标并不是绘制完美的UML图——而是构建能为真实用户带来实际价值的系统。


📌 作者注(2025–2026):
随着团队转向以产品为中心以价值为导向,以及协作式开发,传统UML图的作用正在演变。«include»和«extend»仍然有用——但只有在克制、清晰且有目的性地使用时。让它们服务于用户,而非图本身。

Sidebar Search
Loading

Signing-in 3 seconds...

Signing-up 3 seconds...