在一般的UML建模过程中,分为以下几个阶段:业务、需求、分析和设计,其中设计又可分为结构分析和行为分析。业务是对商业模型的深刻理解,从商业模型里面提取出业务需求,然后把需求分解成一系列的用例。分析和设计是在用例的基础上,对商业模型的结构和行为进行详细具体的描述。结构分析一般是用类图,类图又可以按照M-V-C模型分为数据类、界面类和控制类。行为分析是描述三种类之间的流程操作关系,一般是用时序图或者状态图来表示。
Use case国内翻译为用例,它描述的是一个操作,而不是一个功能。传统的软件模型设计喜欢在需求分析把业务分解成功能模块,这样的弊端就是混淆了需求和设计的界限,因为功能模块的划分牵涉到系统的概要设计。在RUP里面提倡用use case来代替功能模块的划分。与功能模块不同的是,用例不是站在开发者的角度,而是站在用户的角度来分解系统,因为用户并不想了解系统的内部结构和设计,他们关心的是系统的服务,即系统是如何去操作的,这就是用例的基本思想。用例模型主要由以下元素组成:
- 参与者(Actor)
参与者是指存在于被定义系统外部并与该系统发生交互的人或其他系统,他们代表的是系统的使用者或使用环境。 - 用例(Use Case)
用例用于表示系统所提供的服务,它定义了系统是如何被参与者所使用的,它描述的是参与者为了使用系统所提供的某一完整功能而与系统之间发生的一段对话。 - 通讯关联(Communication Association)
通讯关联用于表示参与者和用例之间的对应关系,它表示参与者使用了系统中的哪些服务(用例),或者说系统所提供的服务(用例)是被哪些参与者所使用的。
三种元素在UML用图形表示如下:
Actor可以是用户,也可以是系统,它的选择取决于用例的边界范围,即用例是由谁来触发的,是用户?还是系统?如果是用户触发的,那么它称为业务用例;如果是系统触发的,它称为系统用例。用例的内容包括了几个操作场景,其中最主要的一个场景称为基本流,它代表用例的主要流程。但是一个用例里面的流程可能包括一些意外情况或者失败场景,那么这些场景就称为备选流。例如,在电话通讯系统里面,通话过程是基本流,而占线或者挂断就是备选流。
描述用例除了用例图,还有用例规约,或者说是用例文档。RUP中提供的用例规约包括这些内容:
- 简要说明 (Brief Description)
简要介绍该用例的作用和目的。 - 事件流 (Flow of Event)
包括基本流和备选流,事件流应该表示出所有的场景。 - 用例场景 (Use-Case Scenario)
包括成功场景和失败场景,场景主要是由基本流和备选流组合而成的。 - 特殊需求 (Special Requirement)
描述与该用例相关的非功能性需求(包括性能、可靠性、可用性和可扩展性等)和设计约束(所使用的操作系统、开发工具等)。 - 前置条件 (Pre-Condition)
执行用例之前系统必须所处的状态。 - 后置条件 (Post-Condition)
用例执行完毕后系统可能处于的一组状态。
基本流的描述一般按照这样的格式:1.每个步骤都有数字编号来表明它的先后顺序;2.每个步骤都有简短的标题来概括它的内容;3.每个步骤要详细描述参与者跟系统之间的交互,一般按照正反两个方面来描述:(1)参与者向系统提交了什么信息;(2)系统作出了什么反应。
备选流除了包括基本流类似的描述外,还包括:
(1) 起点:备选流从事件流的哪一步开始;
(2) 条件:在什么条件下触发;
(3) 动作:备选流下系统采取了哪些操作;
(4) 恢复:备选流结束后,用例如何继续。
有时候为了体现用例之间的业务关系,提高系统的可维护度和一致性,用例之间可以抽象出包含(include)、扩展(extend)和泛化(generalization)这几种关系。
包含:在一些模型中,很多用例都会包括一些相同的行为,而我们就可以把这些相同的行为单独抽象成一个用例,然后用其他的用例来包含这个用例。从而避免在多个用例里面重复设计一个操作,也避免同一个操作在不同的用例里面的描述出现不一致。需要修改的时候,也只需要一个用例,避免修改多个用例出现的不一致和重复工作。
例如,一个ATM系统里面,如果银行客户的查询、提款和转帐操作都需要打印回执,那么我们就可以把打印回执这个操作提取出来称为一个用例,而原有的查询、提款和转帐操作都可以包含这个用例,提高系统的可维护性。
扩展:扩展是将事件流程里面一些相对独立并且可选的动作扩展为新的用例,并且在基用例的扩展点进行扩展。它与包含的区别是,包含的事件是必须存在的动作,而扩展是提供一些备选的动作。扩展也可以抽象为基用例的备选流,扩展出来的用例可以让基用例变得更加简练。
例如,在电话业务里面,在基本通话业务的基础上可以扩展一些增值业务,比如语音信箱、呼叫转移和呼叫等待等。
泛化:泛化也叫继承,如果多个用例之间有同样的 结构、行为的时候,我们可以把它们的共性抽象为父用例,其他用例作为泛化关系中的子用例。
例如,用户执行上传操作,他有可能上传文档,也有可能上传图片,或者上传视频,但是它们都可以抽象成为上传功能。