用例图
对于系统工程师团队来说,指定系统用例是一种常见的设计活动。SysML用例图 可以为这种活动提供支持。用例图可以显示各种类型的元素和关系,以说明系统提供 的服务信息,以及需要服务的利益相关者的信息。
1、目的
用例图会简洁地传递一系列用例一系统提供的外部可见服务——以及触发和参 与用例的执行者。用例图是系统的一种黑盒视图,因此也很适合作为系统的情境图。
2、何时创建用例图
用例图是一种分析工具,一般会在系统生命周期的早期创建。系统分析师可能会 枚举各种用例,然后在系统概念和操作(ConOps)的开发阶段创建用例图。在某些方 法中,分析师会在系统生命周期的需求引出和指定阶段,以基于文本的功能性需求方 式创建用例。之后,系统架构师会分析系统级别的用例,以导出和分配子系统,并在 架构设计阶段创建组件级别的用例。
3、什么是用例
在详细讨论用例图之前,清晰地理解用例非常重要。作为开头,我要先介绍一些 很权威的资料。
在《统一建fe语言参考手册(第二版)》(The Unified Modeling Language Reference Mannal, second edition)中,James Rumbaugh、Ivar Jacobson 和 Grady Booch 把用例定义为“特定的一系列动作,包括变种系列动作和错误系列动作,系统、子系统或 者类可以通过与外部对象交互来执行,以提供值的服务。”
在《编写也效用例》(Writing Effectine Use Case) 一书的第一页,Alistair Cockburn是这样解释用例的:
用例会捕获系统利益相关者之间关于系统行为的契约。用例会描述系统 响应一种叫做主执行者的利益相关者请求时,在各种条件下的行为。主执行 者会初始化与系统的交互以完成某些目的。系统做出响应,保护所有利益相 关者的利益。不同序列的行为或者场景可以折叠,这依赖于特定请求,以及 请求的环境。用例会把那些不同的场景搜集在一起。
以下是你在列举系统用例的时候需要时刻记住的关键点。
- 用例是系统将会执行的一种服务 种行为。因此用例名称总会是一个动词短语(像发送命令)
- 系统所执行的所有行为并非都是用例。用例只是系统行为的子集,是外部执行 者能够直接触发或者参与的那些行为。
- 执行者可以是一个人或者一个外部系统,执行者和你的系统之间存在接口。
- 触发用例的执行者叫做主执行者。参与到用例中的执行者叫做次执行者。主执 行者也可以是次执行者。 .
- 一个用例都应该代表主执行者的目的。你要从执行者的角度而不是系统的角度来 为用例起名字——那个动词短语。例如,如果卫星的飞行控制器需要发送命 令,那么用例的名称应该是发送命令而不是接收命令。
- 用例名称不会传达大量信息。你要为每个用例创建用例说明书,以讲述系统和 它的执行者会如何协作来达成用例目标。
3.1用例说明书
用例说明书会传达主执行者触发用例的时候发生的情况。用例说明书在传统上是 文字文档。Alistair Cockburn在他的书籍《编写有效用例》中提供了一种很好的用例说明书格式。
- 用例名称:一个动词短语
- 范围:拥有(提供)用例的实体(例如,组织、系统、子系统或者组件的名称)
- 主执行者:触发用例的执行者(用例会代表该执行者的目标)
- 支持(次要)执行者:为系统提供服务的执行者(通过执行动作参与到用例中)
- 利益相关者:和系统行为之间有既定利益关系的某人或某物
- 预置条件:必须满足才能让用例开始的条件
- 保证(后置条件):在用例结束的时候必须为真的条件 □触发器:让用例开始的事件
- 主要成功场景:没有出现任何错误的场景(一系列步骤)
- 扩展(可置换分支):可置换的系列步骤,它们从主要成功场景分支出来
- 相关信息:你的项目为了得到额外信息而需要的内容
你也可以使用SysML活动图创建图形化的用例说明书。活动图要比传统文字形 式的用例说明书更简洁、更清晰。因此,很多建模者会犯这样的错误,在头脑构思用 例描述的时候就使用建模工具创建活动图。这种实践会阻碍创造力。你需要首先关注 描述;撰写好文字描述,清晰、正确地表述执行者在执行用例的时候,会如何与系统 交互。一旦你开始创建活动图,就会花费大量时间和精力在活动图的布局上,那会让 你无法专心进行清晰、正确的说明。我总是建议团队中的设计师首先以文字形式记录 描述(使用上面显示的模板),和利益相关者一起精炼那些描述.然后再使用建模工具 在活动图上以可视化的方式来表达那些描述(你可以阅读第6章以了解更多关于活动 图的知识)。
需要提前警告的是,通常在第一次创建用例的时候,范围会太大,层次会太高。 在试图编写用例说明书的时候这会出现问题。那样的描述对于你确定正常(成功)场 景,会有太多要决定的点,以及太多执行路径。你可以认为这是一盏红灯。你需要使 用更准确的动词,或者在谓语上包含限定词,创建一系列更细粒度的用例,从而细化 每个用例。例如,发送命令这个描述看起来太泛泛了,因为它包括多种不同的命令生 成方式,以及多个用来传输的通道。成功场景有多个变种。你可以细化这个用例,创 建出以下系列用例:
- 通过上行线路发送实时命令
- 通过前行线路发送实时命令
- 通过上行线路发送存储的命令
- 通过前行线路发送存储的命令
当用例只拥有一个主要成功场景的时候,它就处在了合适的粒度级别上。所有通 过用例说明书表达的其他执行路径都应该是错误或者异常序列。
3.2用例与场景
用例和场景并不是同义词。通过用例执行的每个路径,从开始到结束是一个独立 的场景。因此,用例至少会包含一个或多个场景。用例至少会包含一个主要成功场 景——也就是正常的执行路径。通常它还会包含额外的场景,代表错误和异常的序 列,那些都是主要成功场景的分支。
一幅SysML序列图很适合用图形化的方式表示单独的场景。常用的技术是仔 细分析单个用例说明书——可能是文字说明,或者是活动图——来创建一系列序 列图,每个场景一幅。这样,如果你采取额外的步骤,为输人和期望的输出指定 值,那么那些序列图还可以承担测试案例的职责(更多关于序列图的信息请见第 7章)。
4、用例图外框
用例图的类别缩写是UC。图的外框代表的模型元素类型可能是以下中的一种:
图5.1中用例图的名称是“系统用例”。图的头部也告诉我们,这幅图代表的是 系统模型中的Behavior包。因此,Behavior包就是图中显示的用例的命名空间。等 同的说法是,Behavior包包含图中显示的用例。
当然,我也可以用别的方式来组织这个模型。我可以选择把系统的用例分离到 单独的包中,其名称会与任务生命周期的阶段相关:Manufacturing Use Cases包、 Launch Use Cases包和Operations Use Cases包。在那种情况下,我会为每个包创建 单独的用例图,并针对每幅图在头部修改模型元素的名称。我还应该给每幅图单独的 名称,从而表达模型专注于哪个方面。
我说这些只是为了指出,模型有很多种组织方式。关键是,模型的组织形式一般会影响图在头部和内容部分显示内容。
5、用例
用例图的标识法是一个椭圆形。你可以显示用例的名称 般是一个动词短语——或者在椭圆中,或者在下方(把名称放在椭圆中更常见一些)。
和模块一样,用例可以泛化,也可以特殊化,这意味着你可以创建并显示从一个 用例到另一个用例的泛化关系。泛化在此的意义和它在模块部分的意义相同:继承。 正如在第3章中所提到的,你可以把这种关系读作“……是一种……”。泛化的标识 法也和第3章中一样:在泛化元素(超类型)末尾带有空心三角形箭头的实线。特殊 化元素(子类型)会出现在线的尾端。
图5.1显示了从发送存储命令用例到发送命令用例的泛化关系。发送存储命令用 例是发送命令用例的子类型,发送实时命令用例也是。这两种子类型会继承超类型 所拥有的所有一切,包括它与其他用例及执行者之间的关系,还有可能与之相关联的 行为(活动、交互或者状态机)。子类型可能会把继承过来的内容重定义得更加特殊, 或者添加超类型并不具备的新关系和行为。
6、系统边界
系统边界(也叫做主题)代表拥有并执行图中用例的系统。系统边界的标识法是 围绕用例的矩形框(不要和图的外框混淆)。主题的名称——显示在矩形的顶部—— 必须是一个名词短语。在之前的图5.1中,系统边界就是DellSat-77卫星。
在ConOps开发过程中,系统边界的名称应是你正在设计的系统的名称。在那 个阶段,你的目标是把系统显示为一个黑盒,并指定它会为环境中的执行者提供的 服务。
稍后,在架构设计过程中,你会从结构上把系统分解为子系统(可能)和组件 (一定会)。在那个阶段,你会为每个子系统,终为每个组件创建新的用例图。当你 这样做的时候,系统边界的名称会是你在描述的子系统或者组件的名称。(如果那时 候仍然叫做“系统”边界会让你感到困扰,那么你可以把它叫做“主题”。)
7、执行者
正如3.8节讨论的,执行者有两种标识法:火柴棍小人,或者是名称前面带有 <>*键字的矩形。在图5.1中,这两种标识法都使用了。回顾一下,这两种标识法对于任何类型的执行者 个人或一个系统——都是合法的。然而,建模者约定俗成,会使用火柴棍小人代表人,矩形标识法代表系统。
和BDD—样,你可以在用例图中显示执行者之间的泛化关系。和之前一样,它 意味着子类型(位于尾端)继成了其超类型(位于三角箭头端)所有结构化和行为特 性。如果超类型和一个用例有关联,那么子类型也会继承那种关联,并能够访问那个 用例。
8、将执行者与用例关联
你可能会在执行者和用例之间创建关联,从而表示执行者与系统交互,以触发和 参与到用例中。第3章讨论了关联的细节。它们在用例图中有着相同的意义:系统操 作时相关联的系统元素之间的链接;执行者的实例可能会触发或者参与到用例的实例 中(也就是实例的执行)。
让我们回顾一下,多重性表示在任意给定的时间内,关系中能够涉及多少个实例。图5.2在关联的地面站雷达端显示的多重性是1..*,在关系的雷达操作者端显示 的多重性是1..2。这表示跟踪卫星轨道用例的一次执行可以涉及一个或多个地面站雷 达单元,以及一个或者两个雷达操作者。
这幅图还在两个关联的用例端显示了 0..*的多重性。这表示在任意给定的时刻, 任意特定的雷达操作者或者地面站雷达单元可能会参与到零个或者更多跟踪卫星轨道的执行中。
我们要小心避免在用例图中出现以下与关联相关的非法事物:
- 你不能在执行者和用例之间创建复合的关联
- 你不能在两个执行者之间创建(任意类型)关联
- 你不能在两个用例之间创建(任意类型)关联
9、基础用例
基础用例是通过关联关系与主执行者连接在一起的任意用例。这意味着基础用例 代表的是主执行者的目标。
图5.1中显示了四种基础用例:通过太阳能电池板发电、执行Hohmann转换、把 红外线传感器指向目标以及获得负荷健康度和状态。其他三种用例是内含用例,我们 会在下一节中讨论。
10、内含用例
内含用例是任意一种用例,它是内含关系的目标——也就是位于箭头端的元素。
内含关系的标识法是带有箭头的虚线,在旁边会有关键字<>。在图5.1中, 发送命令用例就是内含用例。
尽管内含关系的标识法和依赖关系非常类似,但内含关系并不是一种依赖;依赖 关系的“客户端一提供方”语义在此并不适用。内含关系表示的是,当源端——关系 的尾端——的用例被触发时,目标端的内含用例也会执行。换句话说,内含用例行为 是源端用例所需要的组成部分。
例如,畀执行者触发了执行Hohmann转换、把红外线传感器指向目标或者获得 负荷健康度和状态的时候,发送命令用例(或者它的一种子类型)也会执行。
遗憾的是,内含关系并没有传达内含行为在源用例中何处执行——开始、中间还 是结朿——只知道它执行了。为了确定内含用例在序列中的何处发生,看图者可能需 要查看与源用例相关的文字描述、活动图或者序列图。
你只能从一个用例到另一个用例使用内含关系。它一般是从基础用例一与主执 行者关联的)11例——向内含用例绘制的。
只苻在你想要表示一些常见的行为,而那些行为又是从多个基础用例中提取出来 的时候,才应该创建内含案例。很多建模新手会滥用内含关系,用来显示单个基础用 例的功能分解。那并不是内含关系存在的目的所在。
作为规则,我不会在用例模型的第一次迭代中创建内含用例。我会首先构思出基 础用例,它会代表主执行者的目标。然后,有了系统利益相关者的输人信息,我会开 始为那些案例编写文字说明,再然后就会出现一种模式。我会注意到多个基础用例会 执行一个通用的步骤(或多个步骤);那时我就会把那些通用的行为重构出来,并把它 表示为一个内含用例。
还有后一个要避免踩人的陷阱:永远不要在主执行者和内含用例之间创建关 联关系。主执行者应该只和代表其目标的基础用例关联。例如,飞行控制器的目标 是执行Hohmann转换,而不是发送命令。发送命令只是完成主执行者目标的必要步骤。
11、扩展用例
才广展用例是任意一种用例,它是扩展关系的源—位于尾端的兀素。i展关系的 标识法是带有箭头的虚线,附近带有关键字<<extend>>。在图5.3中,切换到TDRS 遥感输人用例就是扩展用例。
和内含关系一样,扩展关系并不是一种依赖,尽管它们的标识法非常类似。扩展关系要传达的是,当目标端的用例 位于关系的箭头端 被触发时,源端的扩展用例可能被选择性地执行。这意味着扩展关系目标端的用例自动完成。
例如,雷达操作者每次触发跟踪卫星轨道用例的时候,切换到TDRS遥感输人用 例也可能会执行——也可能不执行;那个扩展用例是否执行,取决于跟踪卫星轨道用 例中的某些触发条件是否满足。
你可以在扩展关系旁边的注释中指定触发条件。但是,在大多数情况下,我更喜 欢在为目标用例创建的活动图中指定触发条件,而不在用例图中指定。
你还可以指定扩展点,在那里扩展用例会在目标用例的行为中生成分支。扩展点 会在目标用例的分隔框中命名。
但是,我的建议是尽量不要那么做。我一般喜欢让用例图尽可能整洁,把扩展用 例的细节(扩展点和触发条件)都放在与目标用例相关联的活动图中。活动图会包含 与扩展点相关的决定点。扩展用例行为会从那个决定点生成分支。
在上个部分,我声明永远不会在用例模型的第一次迭代中创建内含用例。这对于扩展用例也一样适用。正如我提到的,我会首先为基础用例编写文字说明。当注意到 多个基础用例包含相同的可选行为时,就会把那些通用的行为重构出来,并将其表示 为扩展用例。
小结
用例图是一种黑盒视图,它代表的是系统所提供的服务,以及需要那些服务并在 触发之后参与到执行过程中的执行者。因此,建模者通常会创建用例图作为系统情境 图——利益相关者在生命周期早期期望看到的系统视图。
用例图可以显示执行者之间以及用例之间的泛化关系 种用于抽象行为的设计技术。你还可以在用例之中显示内含关系和扩展关系——用于重构多个高层次服务 拥有的通用行为的技术。
|