任何建模语言都以静态建模机制为基础,标准建模语言UML也不例外。
UML的静态建模机制包括
用例图(Use case diagram)、类图(Class diagram)、对象图(Object diagram )、
包(Package)、构件图(Component diagram)和配置图(Deployment diagram)。
1. 用例图
------------
(1) 用例模型(Use case model)
用例模型描述的是外部执行者(Actor)所理解的系统功能。
用例模型用于需求分析阶段,
它的建立是系统开发者和用户反复讨论的结果,
表明了开发者和用户对需求规格达成的共识。
首先,它描述了待开发系统的功能需求;
其次,它将系统看作黑盒,从外部执行者的角度来理解系统;
第三,它驱动了需求分析之后各阶段的开发工作,
不仅在开发过程中保证了系统所有功能的实现,
而且被用于验证和检测所开发的系统,
从而影响到开发工作的各个阶段和 UML 的各个模型。
在UML中,
一个用例模型由若干个用例图描述,
用例图主要元素是用例和执行者。
(2) 用例(use case)
从本质上讲,一个用例是用户与计算机之间的一次典型交互作用。
在UML中,
用例被定义成系统执行的一系列动作,动作执行的结果能被指定执行者察觉到。
在UML中,用例表示为一个椭圆。
概括地说,用例有以下特点:
·用例捕获某些用户可见的需求,实现一个具体的用户目标。
·用例由执行者激活,并提供确切的值给执行者。
·用例可大可小,但它必须是对一个具体的用户目标实现的完整描述。
(3) 执行者(Actor)
执行者是指用户在系统中所扮演的角色。
其图形化的表示是一个小人。
不带箭头的线段将执行者与用例连接到一起,
表示两者之间交换信息,称之为通信联系。
执行者触发用例,并与用例进行信息交换。
单个执行者可与多个用例联系;
反过来,一个用例可与多个执行者联系。
对同一个用例而言,
不同执行者有着不同的作用:
他们可以从用例中取值,也可以参与到用例中。
需要注意的是执行者在用例图中是用类似人的图形来表示,
尽管执行的,但执行者未必是人。
例如,执行者也可以是一个外界系统,
该外界系统可能需要从当前系统中获取信息,
与当前系统有进行交互。
通过实践,我们发现执行者对提供用例是非常有用的。
面对一个大系统,要列出用例清单常常是十分困难。
这时可先列出执行者清单,
再对每个执行者列出它的用例,
问题就会变得容易很多。
(4) 使用和扩展(Use and Extend)
使用和扩展是两种不同形式的继承关系。
当一个用例与另一个用例相似,
但所做的动作多一些,就可以用到扩展关系。
当有一大块相似的动作存在于几个用例,
又不想重复描述该动作时,就可以用到使用关系。
(5) 用例模型的获取
几乎在任何情况下都会使用用例。
用例用来获取需求,规划和控制项目。
用例的获取是需求分析阶段的主要任务之一,
而且是首先要做的工作。
大部分用例将在项目的需求分析阶段产生,
并且随着工作的深入会发现更多的用例,
这些都应及时增添到已有的用例集中。
用例集中的每个用例都是一个潜在的需求。
a. 获取执行者
获取用例首先要找出系统的执行者。
可以通过用户回答一些问题的答案来识别执行者。
以下问题可供参考:
·谁使用系统的主要功能(主要使用者)。
·谁需要系统支持他们的日常工作。
·谁来维护、管理使系统正常工作(辅助使用者)。
·系统需要操纵哪些硬件。
·系统需要与哪些其它系统交互,包含其它计算机系统和其它应用程序。
·对系统产生的结果感兴趣的人或事物。
b. 获取用例
一旦获取了执行者,就可以对每个执行者提出问题以获取用例。
以下问题可供参考:
·执行者要求系统提供哪些功能(执行者需要做什么)?
·执行者需要读、产生、删除、修改或存储的信息有哪些类型。
·必须提醒执行者的系统事件有哪些?
或者执行者必须提醒系统的事件有哪些?
怎样把这些事件表示成用例中的功能?
·为了完整地描述用例,还需要知道执行者的某些典型功能能否被系统自动实现?
还有一些不针对具体执行者问题(即针对整个系统的问题):
·系统需要何种输入输出?输入从何处来?输出到何处?
·当前运行系统(也许是一些手工操作而不是计算机系统)的主要问题?
需要注意,最后两个问题并不是指没有执行者也可以有用例,
只是获取用例时尚不知道执行者是什么。
一个用例必须至少与一个执行者关联。
还需要注意:不同的设计者对用例的利用程度也不同。
2. 类图、对象图和包
----------------------------
(1) 类图
类图(Class Diagram)描述类和类之间的静态关系。
与数据模型不同,它不仅显示了信息的结构,同时还描述了系统的行为。
类图是定义其它图的基础。
在类图的基础上,状态图、合作图等进一步描述了系统其他方面的特性。
(2) 类和对象
对象(Object)与我们对客观世界的理解相关。
我们通常用对象描述客观世界中某个具体的实体。
所谓类(Class)是对一类具有相同特征的对象的描述。
而对象是类的实例(Instance)。
建立类模型时,我们应尽量与应用领域的概念保持一致,
以使模型更符合客观事实,易修改、易理解和易交流。
类描述一类对象的属性(Attribute)和行为(Behavior)。
在UML中,
类的可视化表示为一个划分成三个格子的长方形(下面两个格子可省略)。
(3) 关联关系
关联(Association)表示两个类之间存在某种语义上的联系。
例如,一个人为一家公司工作,一家公司有许多办公室。
我们就认为人和公司、公司和办公室之间存在某种语义上的联系。
在分析设计的类图模型中,
则在对应人类和公司类、公司类和办公室类之间建立关联关系。
关联的方向
关联可以有方向,表示该关联单方向被使用。
关联上加上箭头表示方向,在UML中称为导航(Navigability)。
我们将只在一个方向上存在导航表示的关联,
称作单向关联 ( Uni-directional Association ),
在两个方向上都有导航表示的关联,
称作双向关联 ( Bi-directional Association )。
关联的命名
既然关联可以是双向的,
最复杂的命名方法是每个方向上给出一个名字,
这样的关联有两个名字,
可以用小黑三角表示名字的方向
聚集(Aggregation)是一种特殊形式的关联。
聚集表示类之间的关系是整体与部分的关系。
一辆轿车包含四个车轮、一个方向盘、一个发动机和一个底盘,
这是聚集的一个例子。
在需求分析中,"包含"、"组成"、"分为……部分"等经常设计成聚集关系。
聚集可以进一步划分成共享聚集(Shared Aggregation)和组成。
例如,课题组包含许多成员,但是每个成员又可以是另一个课题组的成员,
即部分可以参加多个整体,我们称之为共享聚集。
另一种情况是整体拥有各部分,
部分与整体共存,
如整体不存在了,部分也会随之消失,
这称为组成(Composition)。
例如,我们打开一个视窗口,它就由标题、外框和显示区所组成。
一旦消亡则各部分同时消失。
在UML中,
聚集表示为空心菱形,组成表示为实心菱形。
(4) 继承关系
人们将具有共同特性的元素抽象成类别,
并通过增加其内涵而进一步分类。
例如,动物可分为飞鸟和走兽,人可分为男人和女人。
在面向对象方法中将前者称为一般元素、基类元素或父元素,
将后者称为特殊元素或子元素。
继承(Generalization)定义了一般元素和特殊元素之间的分类关系。
在UML中,
继承表示为一头为空心三角形的连线。
(5) 依赖关系
有两个元素X、Y,
如果修改元素X的定义可能会引起对另一个元素Y的定义的修改,
则称元素Y依赖(Dependency)于元素X。
在类中,依赖由各种原因引起,
如:
一个类向另一个类发消息;
一个类是另一个类的数据成员;
一个类是另一个类的某个操作参数。
如果一个类的界面改变,它发出的任何消息可能不再合法。
(6) 类图的抽象层次和细化(Refinement)关系
需要注意的是,
虽然在软件开发的不同阶段都使用类图,
但这些类图表示了不同层次的抽象。
在需求分析阶段,类图是研究领域的概念;
在设计阶段,类图描述类与类之间的接口;
而在实现阶段,类图描述软件系统中类的实现。
按照Steve Cook和John Dianiels的观点,
类图分为三个层次。
需要说明的是,这个观点同样也适合于其他任何模型,只是在类图中显得更为突出。
概念层
概念层(Conceptual)类图描述应用领域中的概念。
实现它们的类可以从这些概念中得出,
但两者并没有直接的映射关系。
事实上,一个概念模型应独立于实现它的软件和程序设计语言。
说明层
说明层(Specification)类图描述软件的接口部分,而不是软件的实现部分。
面向对象开发方法非常重视区别接口与实现之间的差异,
但在实际应用中却常常忽略这一差异。
这主要是因为OO语言中类的概念将接口与实现合在了一起。
大多数方法由于受到语言的影响,也仿效了这一做法。
现在这种情况正在发生变化。
可以用一个类型(Type )描述一个接口,
这个接口可能因为实现环境、运行特性或者用户的不同而具有多种实现。
实现层
只有在实现层(Implementation)才真正有类的概念,并且揭示软件的实现部分。
这可能是大多数人最常用的类图,
但在很多时候,说明层的类图更易于开发者之间的相互理解和交流。
理解以上层次对于画类图和读懂类图都是至关重要的。
但是由于各层次之间没有一个清晰的界限,
所以大多数建模者在画图时没能对其加以区分。
画图时,要从一个清晰的层次观念出发;
而读图时,则要弄清它是根据哪种层次观念来绘制的。
要正确地理解类图,
首先应正确地理解上述三种层次。
虽然将类图分成三个层次的观点并不是UML的组成部分,
但是它们对于建模或者评价模型非常有用。
尽管迄今为止人们似乎更强调实现层类图,
但这三个层次都可应用于UML,而且实际上另外两个层次的类图更有用。
细化是UML中的术语,
表示对事物更详细一层的描述。
两个元素A、B描述同一件事物,
它们的区别是抽象层次不同,
若元素B是在元素A的基础上的更详细的描述,
则称元素B细化了元素A,或称元素A细化成元素B。
细化的图形表示为由元素B指向元素A的、
一头为空心三角的虚线(千万不要把方向颠倒了!)。
细化主要用于模型之间的合作,
表示开发各阶段不同层次抽象模型的相关性,
常用于跟踪模型的演变。
(7) 约束
在UML中,
可以用约束(Constraint)表示规则。
约束是放在括号"{}"中的一个表达式,
表示一个永真的逻辑陈述。
在程序设计语言中,约束可以由断言(Assertion)来实现。
(8) 对象图、对象和链
UML中
对象图与类图具有相同的表示形式。
对象图可以看作是类图的一个实例。
对象是类的实例;
对象之间的链(Link)是类之间的关联的实例。
对象与类的图形表示相似,
均为划分成两个格子的长方形(下面的格子可省略)。
上面的格子是对象名,对象名下有下划线;
下面的格子记录属性值。
链的图形表示与关联相似。
对象图常用于表示复杂的类图的一个实例。
(9) 包
一个最古老的软件方法问题是:
怎样将大系统拆分成小系统。
解决这个问题的一个思路是将许多类集合成一个更高层次的单位,
形成一个高内聚、低耦合的类的集合。
这个思路被松散地应用到许多对象技术中。
UML中这种分组机制叫包(Package)
(10) 其他模型元素和表示机制
类图中用到的模型元素和表示机制较为丰富,
由于篇幅的限制,这里不能一一介绍。
主要还有以下模型符号和概念:
类别模板(Stereotype)、界面(Interface)、
参数化类(P arameterized Class)也称模板类(Template)、
限定关联(Qualified Association)、多维关联(N-ary Association)、
多维链(N-ary Link)、派生(Derived)、类型(Type)和注释(Note)等。
(11) 使用类图的几个建议
类图几乎是所有OO方法的支柱。
采用标准建模语言UML进行建模时,
必须对UML类图引入的各种要素有清晰的理解。
以下对使用类图进行建模提出几点建议:
*不要试图使用所有的符号。
从简单的开始,例如,类、关联、属性和继承等概念。
在UML中,有些符号仅用于特殊的场合和方法中,只有当需要时才去使用。
*根据项目开发的不同阶段,用正确的观点来画类图。
如果处于分析阶段,应画概念层类图;
当开始着手软件设计时,应画说明层类图;
当考察某个特定的实现技术时,则应画实现层类图。
*不要为每个事物都画一个模型,应该把精力放在关键的领域。
最好只画几张较为关键的图,经常使用并不断更新修改。
使用类图的最大危险是过早地陷入实现细节。
为了避免这一危险,应该将重点放在概念层和说明层。
如果已经遇到了一些麻烦,
可以从以下几个方面来反思你的模型。
*模型是否真实地反映了研究领域的实际。
*模型和模型中的元素是否有清楚的目的和职责
(在面向对象方法中,系统功能最终是分配到每个类的操作上实现的,
这个机制叫职责分配)。
*模型和模型元素的大小是否适中。
过于复杂的模型和模型元素是很难生存的,应将其分解成几个相互合作的部分。
3. 构件图和配置图
----------------------------
构件图(Component diagram)和配置图(Deployment diagram)
显示系统实现时的一些特性,
包括源代码的静态结构和运行时刻的实现结构。
构件图显示代码本身的结构,
配置图显示系统运行时刻的结构。
(1) 构件图构件图显示软件构件之间的依赖关系。
一般来说,软件构件就是一个实际文件,
可以是源代码文件、二进制代码文件和可执行文件等。
可以用来显示编译、链接或执行时构件之间的依赖关系。
(2) 配置图配置图描述系统硬件的物理拓扑结构以及在此结构上执行的软件。
配置图可以显示计算结点的拓扑结构和通信路径、
结点上运行的软件构件、软件构件包含的逻辑单元(对象、类)等。
配置图常常用于帮助理解分布式系统。
(3) 结点和连接
结点(Node)代表一个物理设备以及其上运行的软件系统,
如一台Unix主机、一个PC终端、一台打印机、一个传感器等。
结点表示为一个立方体,结点名放在左上角。
结点之间的连线表示系统之间进行交互的通信路径,
在UML中被称为连接(Connectio n)。
通信类型则放在连接旁边的"《》"之间,表示所用的通信协议或网络类型。
(4) 构件和界面
在配置图中,构件代表可执行的物理代码模块,如一个可执行程序。
逻辑上它可以与类图中的包或类对应。
因此,配置图中显示运行时各个包或类在结点中的分布情况。
在面向对象方法中,类和构件等元素并不是所有的属性和操作都对外可见。
它们对外提供了可见操作和属性,称之为类和构件的界面。
界面可以表示为一头是小园圈的直线。
配置图中还显示了构件之间的依赖关系
(5) 对象(Object)
一个面向对象软件系统中可以运行很多对象。
由于构件可以看作与包或类对应的物理代码模块,
因此,构件中应包含一些运行的对象。
配置图中的对象与对象图中的对象表示法一样。
标准建模语言UML的静态建模机制是采用UML进行建模的基础。
我们认为,
熟练掌握基本概念、区分不同抽象层次以及在实践中灵活运用,
是三条最值得注意的基本原则。