关于Use Case之间的关系,绝大部分书籍一带而过,大概是因为很简单。但是却是在实际应用中争论和疑惑蛮多的问题之一。
通常来说,用例之间有两种关系:包含(include),扩展(extend)。这也是UML 2.2官方规范中说明的两种关系。
包含(include)关系为用例建模提供了从两个或更多的Use Case的描述中抽取通用部分的能力。所以,在描述Use Case之前就开始抽取包含用例是不可取的;再有,如果没有两个以上的Use Case来包含这个Use Case,那么这个抽取是毫无意义的。
扩展(extend)关系提供了使用另外的可选流程来补充或插入到一个已存在的Use Case中的能力。因此,这是一种能够扩展原Use Case却不用对原来的Use Case进行重新描述的方法。
这两种关系在实际应用中究竟应如何区别有时会很难把握,建议可以根据如下特征来区分。
包含关系:
1. 对基用例来说,如果缺少了被包含用例则是不完整的。即,被包含用例是基用例不可缺少的一部分。
2. 被包含用例对基用例是可见的,即基用例知道被包含用例的存在。
3. 被包含的用例通常应被两个以上的其他用例所包含,否则应该考虑一下是否应该使用包含。
例子:校内网(xiaonei.com)中,“查找好友”可能为“发送消息”和“删除好友”所包含。
扩展关系:
1. 如果去掉扩展关系,基用例仍然完整。
2. 扩展用例本身具有独立的功能,而非从其他用例抽取出来的。
3. 基用例对扩展用例是可见的,而扩展用例对基用例不可见。也即,基用例不知道有扩展用例的存在。
Kurt Bittner等在《Use Case Modeling》给出了可能需要使用扩展用例的几种情况:
l 描述一些对系统的基本功能来说是可选的特性。例如,可能是一些由系统提供甚至可从第三方购买的一些可选的系统特性。
l 描述一些可能使主流程变得很晦涩难懂的、十分复杂的错误或异常处理过程。例如,有些分支流程巨长,尤其是比主流程还长。
l 为一些特殊顾客定制的需求。
l 由于范围管理和发布管理的需要。例如,有些系统特性或行为在后来的发布中才会包括,那么在后来的项目中可以用扩展用例来对系统功能进行扩展。
例子:收邮件时,忘记密码了,需要找回密码。“找回密码”对“收邮件”来说是个扩展用例。
如果在有些情况下你仍然觉得很难决定应该使用<<include>>还是<<extend>>,那么停止纠结,就用<<include>>吧(因为包含比扩展更容易让人懂,而扩展比包含更容易让人懵,:-))!“错”就“错”了,总比无谓的浪费时间好。
另外,你可能偶尔还会看到<<uses>>关系,这见于较早版本的UML中,以前的<<uses>>和<<includes>>被现在的<<include>>取代,可以将之理解为<<include>>关系。
还有Generalization,虽然在官方规范中未明确说明,但是偶尔会有人讨论Use Case之间的Generalization关系。我对此不欲多说,因为在我几年的Use Case Modeling经历中,我真的没有觉得我需要在Use Case间使用Generalization关系的场景。本着“简单”和“沟通”的原则,忘记它吧!
虽然前面说了这么多,可是最后我想说,Use Case之间不要随便搞“关系”。很多人喜欢把Use Case图画得很玄乎,关系搞得很复杂!很不幸,方向错了。Kurt Bittner等的《Use Case Modeling》中说:If there is one thing that sets teams down the wrong path, it is the misuse of the use-case relationships include,extend and generalization. Alistair在《编写有效用例》中也十分强调,Use Case真正有价值的是Use Case描述,所谓的用例间的关系往往价值不大还会适得其反。