对于规模较大的用例,建模过程中经常会发现多个用例存在共享相同的子目标或子行为的情况。为避免重复并实现共享,UML提供包含(«include»)机制允许一个用例包含另一个用例。当然,被包含的用例可以是一个被多个其他用例(此时,该用例称为“基本用例”)同时包含的用例,也可以仅仅被一个其他用例包含,此时建模者使用包含机制的目的一般是将大型复杂用例拆解为更小的、更易处理的用例。
作为建模者必须清楚,被包含用例是基本用例的一部分,也就是说基本用例如果缺失被包含用例它将是不完整的,基本用例的目标也就将因此而无法实现,被包含用例与基础用例是一个有机组合的整体,不可独立存在。
提取公共行为创建«include»用例的一般步骤如下:
1.识别出多个用例中共有的目标行为,并创建一个用例包含该行为;
2.从原始用例提取共有目标相关的需求与描述(提取过的原始用例称为基本用例);
3.将提取出的相关需求与描述放置到一个新用例(被包含用例)中,如果被包含用例已存在,则复用它;
4.使用从基本用例到被包含用例的虚线箭头将两个用例连接起来;
5.将连接基本用例与被包含用例的虚线标记为“«include»”;
6.除非被包含用例需要仅与其自身关联而不与基本用例关联的参与者,否则不应将参与者与被包含用例连接,如果参与者同时参与基本用例和被包含用例,则该参与者只需与基本用例连接即可;
7.对于其他也应包含新的被包含用例的原始用例,从第2步开始重复上述过程。
图 1展示了一个使用包含用例的例子,对于读者到图书馆“借书”和“还书”这两个用例,它们都包含了“检查借书证状态”这个用例。无论读者借书还是还书,系统都将检查借书证的状态,例如借书证的有效期等。如果不执行“检查借书证状态”这个用例,则“借书”和“还书”两个用例都将无法完成,“检查借书证状态”这个被包含用例是“借书”和“还书”两个基本用例的不可缺少的组成部分。
图 1 基础用例共享被包含用例
在上图中,读者是触发“借书”和“还书”用例的参与者,同时读者也是“检查借书证状态”用例的触发者,所以读者也是“检查借书证状态”的参与者,但由于读者已经与它的基本用例建立关联,所以不需要在读者与“检查借书证状态”之间重复建立关联。
假设用例“检查借书证状态”不能独立在当前系统中完成,而是必须借助另外一个名为“借书证管理系统”的参与者来获得借书证状态,此时被包含用例可以与名为“借书证管理系统”的参与者建立关联,如图 2所示。
图 2 建立被包含用例与参与者关联
如前所述,使用«include»用例不仅可以用在将多个用例共通部分抽取出来的场景,也可以用在将大型复杂用例进行分解的场景。例如,对储户去银行/ATM机取钱的场景,可以建立一个名为“取钱”的用例,但执行该用例涉及的环节比较多,因而可以考虑将其分解为多个“小”用例,然后“取钱”用例通过«include»关系将它们整合到一起,如图 3所示。
图 3 复杂用例分解
在用例之间存在继承关系时,使用被包含用例建模要注意用例之间的继承关系包括对用例的包含。例如在图书馆借阅场景下,假定借阅人群被划分为两类(或两档),能够“借阅图书”的“普通借阅者”和能够“借阅视听材料”的“视听借阅者”,其中视听借阅者拥有普通借阅者的所有权限,即视听借阅者也可以借阅图书,而用例“借阅视听材料”与“借阅图书”高度相似,只是被借阅的材料更宽泛。因而在参与者“视听借阅者”与“普通借阅者”之间、用例“借阅视听材料”和“借阅图书”之间都存在泛化关系,如图 4所示。
图 4 继承用例使用包含用例
在执行用例“借阅图书”和“借阅视听材料”时,用例都会去检查借阅者的借书证状态。如果在建模时将这个过程独立建模为用例“检查借书证状态”,则只需要在基本用例“借阅图书”和被包含用例“检查借书证状态”之间建立«include»关系即可。用例“借阅视听材料”也必须包含“检查借书证状态”才能够完整达成用例目标,但由于用例“借阅视听材料”继承于用例“借阅图书”,而用例“借阅图书”包含了用例“检查借书状态”,继承使得用例“借阅视听材料”已经包含用例“借阅图书”的特性,其中包括“借阅图书”对用例“检查借书证状态”的包含关系,因此不需要重复在用例“借阅视听材料”和“检查借书证状态”之间建立«include»关系。
基本用例调用被包含用例与程序中一个函数调用另一个函数完全不同,基本用例调用被包含用例没有调用参数,被包含用例运行完毕后也没有返回值,用例之间的包含关系更类似“复制-粘贴”——将被包含用例复制后粘贴到基本用例的适当位置。
最后,通过上述说明还可以推导出一个结论:一个基本用例可以包含多个被包含用例;一个被包含用例也可以被多个基本用例包含。