UML简介2用例图

2 用例图

用例图可以让我们描述一个系统可能的使用场景(用例)。它表达了系统应该做什么,但不涉及任何实现细节,如数据结构、算法等。这些细节将由其他图来描述,如类图或交互图。用例图还对系统的哪些用户使用哪些功能进行了建模,也就是说,用例图表达了谁将实际使用即将构建的系统。

用例是许多面向对象开发方法的基本概念。它应用于整个分析和设计过程。用例表示客户希望系统做什么,也就是客户对系统的要求。在很高的抽象层次上,用例显示了未来系统的用途。用例图还可以用来记录现有系统的功能,并追溯记录哪些用户可以使用哪些功能。
具体来说,我们可以利用用例图来回答以下问题:

  • 描述的是什么?(系统)
  • 谁与系统交互?(角色)
  • 角色能做什么?

用例图只提供了几个语言元素。乍一看,这种图似乎非常简单易学易用。但实际上,用例图是一种极易被低估的图表。用例图的内容表达了客户对将要开发的系统的期望。该图记录了系统应满足的要求。这对详细的技术设计至关重要。如果用例被遗忘或指定得不精确或不正确,在某些情况下后果会非常严重:开发和维护成本增加、用户不满意等。结果,系统的使用效果大打折扣,开发系统的投资也没有带来预期的回报。尽管软件工程和需求分析方法不是本书的主题,但我们还是要简要说明为什么必须非常谨慎地创建用例。此外,我们还讨论了经常出错的地方,以及如何通过系统化的方法避免这些错误。

2.1 用例

用例描述了待开发系统的预期功能。它包括使用该系统时要执行的一系列功能。用例为与该用例通信的角色提供有形的利益。用例图不包括用例的内部结构和实际执行。一般来说,用例是通过调用角色或触发事件(简言之,触发器)触发的。触发事件的一个例子是:触发学期结束,因此必须执行用例 "签发证书"。

用例是在需求分析的基础上,通过收集客户愿望和分析自然语言中指定的问题而确定的。不过,用例也可以用来记录系统提供的功能。用例通常用一个椭圆来表示。用例名称直接在椭圆内或椭圆下指定。另外,用例也可以用一个矩形来表示,矩形的中心是用例名称,右上角是一个小椭圆。但最常用的是第一个替代符号,即包含用例名称的椭圆。

所有用例的集合描述了软件系统提供的功能。这些用例一般都集中在一个矩形内。这个矩形象征着要进行系统描述的系统的边界。下图中的示例显示了学生管理系统,该系统提供三个用例:(1) 查询学生数据,(2) 颁发证书,(3) 宣布考试。这些用例可由行为者"教授"触发。

2.2 角色(Actors)

参与者(Actors)又名角色、演员,由简笔画、矩形或可自由定义的符号表示。

角色类型:

  • 人类/非人类
  • 主动/被动
  • 基本/次要

交互涉及系统使用的角色,这意味着该角色是一个被动的角色,为用例的执行提供功能。 上图示例 (a) 中,Professor是主动角色,而电子邮件服务器是被动角色。

用例图还可以包含主要和次要角色,主角从用例的执行中获得实际收益(在我们的示例中,这是教授),而配角电子邮件服务器没有从用例的执行中获得直接收益。 示例 (b) 中看到的,配角不一定必须是被动的。 教授和学生都积极参与用例考试的执行,其中主要受益者是学生。相比之下,教授从考试中获得的好处较低,但对于用例的执行是必要的。

2.3 关联

关联表示角色与系统通信并使用特定功能。每个角色都必须与至少一个用例进行通信。 否则,我们将拥有一个不与系统交互的角色者。 同样,每个用例必须与至少一个角色有关系。

关联始终是二元的,这意味着它始终在用例和角色之间指定。可以为关联端指定多重性。 如果为参与者的关联端指定了大于1的重数,则意味着不止一个角色参与用例的执行。下图一到三名学生和一名助理参与用例进行口语考试的执行。 如果没有为角色的关联端指定多重性,则默认值为1。

角色并不代表具体的用户--它们代表角色用户所采用的角色。如果用户采用了相应的角色,则该用户有权执行与该角色相关的用例。特定用户可以同时采用和设置多个角色。例如,一个人可以作为助理参与某项作业的提交,也可以作为学生参与另一项作业的提交。

2.4 角色之间的关系

角色通常有共同的属性,允许查看学生数据的不仅有教授,还有助理(即所有研究人员)。可以将角色之间描述为继承关系(泛化)。当角色Y继承自角色X(超行为者)时,Y就涉及到X所涉及的所有用例。简单地说,泛化表达的是一种"是"的关系。

角色到超级角色之间用一条线表示,超级角色端有大的三角形箭头。
抽象角色的使用只有在继承关系中才有意义:子角色的共同属性被归类并在一个点上进行描述,即共同的抽象超级角色。
泛化是面向对象的一个基本概念,可应用于UML的许多不同语言元素。

2.5 用例之间的关系

用例也可以与其他用例发生关系。

用例 "Announce lecture"和"Assign lecturer"是"包含"关系,其中"Announce lecture"是基本用例。因此,每当宣布新讲座时,也必须执行用例Assign lecturer。教授参与了这两个用例的执行。由于所包含的用例可以独立于基本用例执行,因此还可以为现有讲座指定更多讲师。

用例可以包含多个其他用例,必须确保不会出现循环。

"Announce lecture"和"Reserve lecture hall"这两个用例是"扩展"关系。当宣布一个新讲座时,有可能(但不是必须)预订一个报告厅。

可以为每个"扩展"关系指定一个条件,该条件必须满足,基本用例才能插入扩展用例的 "条件"行为。

用例之间也可以进行泛化。

2.6 关系示例

为了再次明确解释用例图中不同关系类型之间是如何相互作用的,让我们看一下图,并讨论这里出现的一些有趣的情况。

  • 用例H继承自用例C。由于用例C是由角色L执行的,因此角色L也必须参与H的执行。因此,用例C和H也可以由角色M或N来执行。

  • 用例J继承自用例B。由于继承关系,用例J的执行涉及到角色O。这样有两个角色O参与了J的执行。

  • 用例F继承自用例G。由于继承关系,角色N参与了用例F的执行。因此在执行F时,会涉及到一个角色N,而且由于角色L、N和M之间的继承关系,也会涉及到一个角色L或一个角色M或另外一个角色者N。

  • 用例F继承自用例G,而I又扩展了用例G,因此这种关系会传递给F。如果G和I是"包含"关系,这种关系也会以同样的方式传递给F。

  • 用例J扩展了用例H,这是B到J和C到H的继承关系的结果。

2.7 创建用例图

首先,您必须确定行为者和用例,然后将它们置于相互关系中。然后详细描述用例。乍一看,这个图似乎很简单,因为涉及的概念很少。但事实上,用例图的创建往往是错误的,错误百出。
因此,我们在此简要介绍一下创建用例的原则。然后,我们将解释用例图建模时应避免的一些典型错误。

2.7.1 确定角色和用例

有两种方法可以为预期的系统设计确定用例:

  1. 分析需求文档
  2. 分析未来用户的期望

需求文档通常是自然语言规范,说明客户对系统的期望。它们应相对准确地记录谁将使用系统以及如何使用系统。如果采用第二种方法查找用例,则必须首先确定角色,必须回答以下问题:

  • 角色
    • 谁使用主要用例?
    • 谁需要日常工作支持?
    • 谁负责系统管理?
    • 系统必须与哪些外部设备/(软件)系统通信?
    • 谁对系统的结果感兴趣?
  • 用例
    • 必须执行的主要任务是什么?
    • 是否想要查询甚至修改系统中包含的信息?
    • 是否希望向系统通报其他系统的变化?
    • 系统中的意外事件是否需要通知用户?

在许多情况下,我们都是以迭代和增量的方式来建立用例模型的。在迭代和增量确定用例的过程中,通常会从"最高级别 "的需求开始,这些需求反映了软件要实现的业务目标。然后继续完善这些需求,直到在技术层面上明确了系统应该能做什么。例如,对大学管理系统的"最高级"要求可能是该系统可用于学生管理。如果对这一要求进行细化,我们就可以定义新生应能在大学注册并参加学习,学生不同课程的成绩应被存储等。

2.7.2 描述用例

为了确保即使是大型用例图也能保持清晰,为用例选择简明扼要的名称极为重要。当出现用例背后的意图及其解释不明确的情况时,您还必须对用例进行描述。同样,确保简明扼要地描述用例也很重要,否则读者有可能只是略读文件。
公认的用例描述长度准则是每个用例大约1-2页。Alistair Cockburn 提出了一种结构化的用例描述方法,其中包含以下信息:

  • 名称
  • 简短描述
  • 前提条件:成功执行的先决条件
  • 后置条件:成功执行后的系统状态
  • 出错情况:与问题领域相关的错误
  • 出错时的系统状态
  • 与用例通信的角色
  • 触发器:启动/开始用例的事件
  • 标准流程:需要采取的各个步骤
  • 替代流程:与标准流程的偏差

上图包含学生管理系统中使用案例"预订讲堂"的描述,虽然非常简单,但完全可以满足我们的要求。标准流程和替代流程可以进一步完善,也可以考虑其他出错情况和替代流程。例如,可以预订一个正在举行活动的报告厅,如果该活动是一场考试,可以在报告厅与另一场考试同时举行,这就意味着需要更少的监考人员。在实际项目中,细节来自客户的要求和愿望。

参考资料

2.7.3 陷阱

不幸的是,在创建用例图时经常会出错。

  • 错误 1:对流程建模

即使在用例图中对整个(业务)流程或工作流建模往往很有诱惑力,但这是对用例图的错误使用。假设我们正在为学生办公室系统建模。如果学生使用领取证书功能,首先必须通知学生证书已准备好,可以到学生办公室领取。当然,讲师必须已将证书发送到学生办公室,即证书已经签发。用例"收集证书"、"发送通知"和"签发证书 "可以按时间顺序连接起来,但不应在用例图中表示出来。其中一个用例提供的功能不属于另一个用例提供的功能,因此这些用例必须独立使用。

  • 错误 2:错误设置系统边界

在对用例图建模时,必须仔细考虑在何处绘制用例图的边界。如前所述,这一点往往并不明确。行为者总是在系统边界之外:
如果它们位于系统内,那么它们就是系统的一部分,因此它们就不能作为角色建模。

上图雇员被描绘在学生管理系统的边界内。当然,学生管理系统也包括雇员。但是,当我们要创建该系统的用例图时,我们必须考虑是要把这些雇员看作行为者,还是看作学生管理系统的一部分。如果他们是系统的一部分,就不能将他们作为角色建模。

  • 错误 3:混合抽象层次

在确定用例时,必须始终确保它们位于同一抽象层次。避免在同一图表中表示"顶级"用例和技术型用例。

在这个示例中,学生数据的管理和打印机的选择(这是系统的一项技术功能)被放在了一起。因此,为避免出现此类错误,应反复进行。首先根据业务目标(在我们的例子中是学生数据管理)创建用例图。然后将这些用例细化到技术要求(选择打印机)。

  • 错误 4:功能分解

用例(即使是包含或扩展的用例)总是可以独立执行的。如果这些用例只能在另一个用例的范围内执行,而不能独立执行,那么它们就不是用例,也就不能作为用例来描述。它们的功能必须包含在使用它们的用例描述中。下图(a)中,用例 "问题证书 "被分解为执行用例所需的各个子功能。这些子功能被建模为用例,尽管有时它们并不是有意义的独立用例,如输入数据。

登录用例也不是问题证书的一部分功能。事实上,用户必须登录并获得足够授权才能执行该用例,这是一个先决条件。
因此,如图(b)所示的简化用例图就足够了。图(a) 中指定的其他信息必须在用例描述中指定。

  • 错误 5:不正确的关联

如果一个用例与两个角色相关联,这并不意味着其中一个角色或另一个角色参与了用例的执行:而是意味着两个角色都是执行用例所必需的。在下图(a)的用例图中,助理和教授都参与了用例的执行,这不是用例的本意。为了解决这个问题,我们可以引入新的抽象角色 "助理研究员"(Research Associate),助理和教授从这个角色继承。现在,角色Employee与用例Issue信息相连。

  • 错误 6:为冗余用例建模

在为用例建模时,很容易为每种可能的情况创建单独的用例。例如下图(a) 中的用例图中,我们为创建、更新和删除课程分别创建了用例。这显示了在系统中编辑课程的不同选项。在图(a)的这样一个小的用例图中,要在如此详细的层次上显示不同的选项是不成问题的。

然而,在对实际应用建模时,用例图很快就会变得难以管理。为了解决这个问题,可以将具有相同目标(即管理课程)的用例分组。这在图(b)中有所体现。然后在标准流程的描述中具体说明各个步骤。

2.7.4 示例

在本章的最后,我们创建了一个用例图,按照以下规范描述了某大学学生处信息系统的功能:

  • 大学的许多重要行政活动都由学生办公室处理。学生可以在这里注册(入学)、注册和退学。入学包括注册,即注册学习。
  • 学生在学生办公室领取证书。证书由工作人员打印。讲师向学生办公室发送评分信息。然后,通知系统会自动通知学生证书已发放。
  • 学生办公室的员工分为两类:a) 专门负责管理学生数据的员工(服务型员工,或 ServEmp);b)完成其他任务的员工(行政员工,或称 AdminEmp),而所有员工(ServEmp 和 AdminEmp)都可以签发信息。
  • 当学生来领取证书时,行政人员会发放证书。行政人员还可以创建课程。创建课程时,他们可以预订讲堂。

要根据此简化规范创建用例图,我们首先要确定参与者及其相互关系。然后确定用例及其相互关系。最后,我们将参与者与用例联系起来。

  1. 确定角色

讲师、学生、ServEmp 和 AdminEmp 类型的员工以及通知系统。由于这两种类型的员工都有共同的行为,即发布信息,因此引入一个共同的超级行为体StudOfficeEmp是合理的,ServEmp和AdminEmp都继承了这个超级行为体。我们假定通知系统不是学生办公室的一部分,因此将其包括在角色列表中。

  1. 确定的用例

规范非常简短。但是,我们知道其目的是对支持学生办公室员工的信息系统进行建模,而不是对学生办公室为学生提供的功能进行建模。如果我们要对后者进行建模,我们就需要一个用例,例如学生参与的 Collect certificate。这个用例没有包含在信息系统中,因为它与证书的收集无关。
但是,打印证书用例却包含在内。要打印,我们自然需要一台打印机。我们是否应该将其添加到行为者列表中?我们不这样做,因为我们认为打印机是建模系统的一个组成部分。

我们还有注册、注册和提款功能。我们可以将这些功能归类到一个用例中,即"管理学生数据",因为它们都是由角色 ServEmp执行的。但是,这样做我们就会丢失预科包括注册学习的信息。

因此,我们没有将三个用例合并为一个用例。我们用"包括"关系来表达注册和注册之间的关系。由于三个用例都与 ServEmp 有关联,我们仍然引入了用例 "管理学生数据",并将用例 "注册"、"入学 "和 "退学 "建模为从该用例继承。为了表示该用例不能实例化,我们将其定义为抽象用例。

讲师可执行发送证书用例。如果证书被发送到学生办公室,受影响的学生就会收到通知。不过,我们没有建立单独的用例 "通知学生"模型,因为根据上述规范,只有在用例"发送证书"的情况下才会通知学生。如果"通知学生"不能独立执行,那么这项活动就不是信息系统的用例。

此外,我们还有用例 "发布信息"、"预留讲堂 "和"创建课程",其中"预留讲堂"是用例"创建课程"的扩展。

  1. 确定关联

请注意,现在我们的行为者比潜在的候选行为者少了两个。不再有任何学生--学生可能不会以我们建模的形式使用信息系统。此外,也不再有通知系统,因为它被认为是学生办公室的一部分。

4.描述用例

3.8 小结

用例图从用户的角度描述了系统的行为。这意味着该图展示了系统提供的功能,但不涉及内部实施细节。系统的边界--系统可以做什么,不可以做什么--已经明确定义。用户(角色)总是在系统之外使用系统的功能,这些功能以用例的形式描述。用例与角色之间的关系称为关联。为了使用例图尽可能紧凑,行为者和用例都支持概括化,这样就可以提取共同属性。用例还可以通过"包含"和"扩展"关系访问其他用例提供的功能。下表概述了最重要的符号元素。

posted @ 2023-10-09 13:52  磁石空杯  阅读(176)  评论(0编辑  收藏  举报