UML泛化用例的新颖阐释
在UML范畴内,参与者以及用例都能够被实施泛化或者特化操作,它们在进行泛化或特化之时遵循着面向对象里泛化与特化的特性。
当存在多种达成用例目标的方式时,用例泛化就显得十分实用。例如在不少需求场景中都需要“付款”,而当下人们的支付方式丰富多样,除了传统的“现金支付”方式外,还可以有“刷卡支付”或者“扫码支付”的选择。刷卡支付包含“信用卡支付”和“借记卡支付”这两种实现途径,扫码支付则能选择“支付宝支付”或者“微信支付”。这些付款用例之间的关系可用图1来进行建模。
图1展示的是用例泛化建模情况。在上图中,用例之间借助泛化来体现它们彼此间的关系,并且图中除了叶子结点用例外,其余的用例都是泛化用例,对泛化用例添加、修改或者删除任何需求或者目标都会自动应用到特化用例上,这是泛化关系中继承特性的具体呈现。
在建模实践中,或许有建模者直接采用上图中的各叶子结点用例来建模,也就是把上图简化成仅有现金支付、信用卡支付、借记卡支付、支付宝支付、微信支付这五个用例,这种建模方式虽说也能达成付款的目标,但却让模型中参与者与用例之间的关系变得复杂起来。下面的两张图(图2和图3)分别是运用泛化关系和不运用泛化关系并且同时加入参与者的建模结果。可以发现,运用泛化关系时,参与者“顾客”只需要和用例“付款”建立关联,而不运用泛化关系时参与者“顾客”就得分别和各个具体的付款用例建立关联,此时虽然用例数量少了,但参与者与用例之间的关系却更加复杂了。
图2呈现的是泛化用例与参与者关联的情况,图3展示的是具体用例与参与者关联的情况。不运用泛化关系建模还存在其他一些问题,比如在实现各个具体的付款用例时,各个用例实际上有大量相似的操作与流程,因而在进行用例场景描述(用例实现)时会产生重复工作。
另外,如果付款用例需要进行修正,在运用泛化关系的模型中,只需要修改“付款”这一个用例就行,而在未运用泛化关系的模型中则需要修改每一个具体的付款用例。
基于泛化关系来建模,还有利于用例的扩展。比如对于“扫码支付”,当前仅仅实现了“支付宝支付”和“微信支付”,后续如果需要追加其他扫码支持,例如“云闪付支付”,只需要在“扫码支付”下特化出一个“云闪付支付”用例就可以了,对模型整体的影响不大。
上图中还用到了“抽象用例”(UML用斜体的用例名称来表示),抽象用例是不能直接实例化或者执行的用例,它代表着一组用例的共同行为和目标,它通常提取并封装多个具体用例的公共步骤或者逻辑,以便实现用例之间的复用和模块化。
建模的时候,参与者与用例可能同时存在泛化关系。例如在图书馆借阅场景中,很多图书馆把读者(借阅者)分成两类,也就是只能借阅图书的普通借阅者和允许借阅视听资源的视听借阅者。视听借阅者也能够借阅图书,也就是说视听借阅者拥有普通借阅者所有的特性,因而可以在视听借阅者与普通借阅者之间建立泛化关系;而借阅视听资源的具体流程与目标和借阅图书是相似的,只是被借对象除了图书外还增加了视听资源,它是借阅图书的一种特化,所以这两个用例之间也存在泛化关系。其建模结果如图4所示。
类似地,在上述图书馆借阅场景中,如果不运用泛化关系,那么视听借阅者就必须与借阅图书用例建立关联,如图5所示。
实际上,在图书馆借阅场景中,与普通借阅者相关联的用例不止一个,如果把它们全部建模,那么在上述用例图中,所有与普通借阅者有关联的用例,视听借阅者也必须通过实线与它们建立关联。
在本文最后,提请读者思考一个问题:在图4中,如果把两个泛化关系任意去掉一个而保留另一个,这个模型描述的场景会变成什么样呢?