Unified Modeling Language ( UML )又称 统一建模语言 或 标准建模语言 ,是始于1997年一个OMG标准,它是一个支持模型化和 软件系统 开发的图形化语言,为 软件开发 的所有阶段提供模型化和可视化支持,包括由 需求分析 到规格,到构造和配置。
面向对象的分析与设计(OOA&D,OOAD)方法的发展在80年代末至90年代中出现了一个高潮,UML是这个高潮的产物。它不仅统一了Booch、Rumbaugh和Jacobson的表示方法,而且对其作了进一步的发展,并最终统一为大众所接受的标准建模语言。
一. 标准建模语言UML的出现
公认的面向对象建模语言出现于70年代中期。从1989年到1994年,其数量从不到十种增加到了五十多种。在众多的建模语言中,语言的创造者努力推崇自己的产品,并在实践中不断完善。但是,OO方法的用户并不了解不同建模语言的优缺点及相互之间的差异,因而很难根据应用特点选择合适的建模语言,于是爆发了一场“方法大战”。90年代中,一批新方法出现了,其中最引人注目的是Booch 1993、OOSE和OMT-2等。
Booch是面向对象方法最早的倡导者之一,他提出了面向对象软件工程的概念。1991年,他将以前面向Ada的工作扩展到整个面向对象设计领域。Booch 1993比较适合于系统的设计和构造。
Rumbaugh等人提出了面向对象的建模技术(OMT)方法,采用了面向对象的概念,并引入各种独立于语言的表示符。这种方法用对象模型、动态模型、功能模型和用例模型,共同完成对整个系统的建模,所定义的概念和符号可用于软件开发的分析、设计和实现的全过程,软件开发人员不必在开发过程的不同阶段进行概念和符号的转换。OMT-2特别适用于分析和描述以数据为中心的信息系统。
Jacobson于1994年提出了OOSE方法,其最大特点是面向用例(Use-Case),并在用例的描述中引入了外部角色的概念。用例的概念是精确描述需求的重要武器,但用例贯穿于整个开发过程,包括对系统的测试和验证。OOSE比较适合支持商业工程和需求分析。
此外,还有Coad/Yourdon方法,即著名的OOA/OOD,它是最早的面向对象的分析和设计方法之一。该方法简单、易学,适合于面向对象技术的初学者使用,但由于该方法在处理能力方面的局限,目前已很少使用。
概括起来,首先,面对众多的建模语言,用户由于没有能力区别不同语言之间的差别,因此很难找到一种比较适合其应用特点的语言;其次,众多的建模语言实际上各有千秋;第三,虽然不同的建模语言大多类同,但仍存在某些细微的差别,极大地妨碍了用户之间的交流。因此在客观上,极有必要在精心比较不同的建模语言优缺点及总结面向对象技术应用实践的基础上,组织联合设计小组,根据应用需求,取其精华,去其糟粕,求同存异,统一建模语言。
1994年10月,Grady Booch和Jim Rumbaugh开始致力于这一工作。他们首先将Booch 93和OMT-2 统一起来,并于1995年10月发布了第一个公开版本,称之为统一方法UM 0.8(Unitied Method)。1995年秋,OOSE 的创始人Ivar Jacobson加盟到这一工作。经过Booch、Rumbaugh和Jacobson三人的共同努力,于1996年6月和10月分别发布了两个新的版本,即UML 0.9和UML 0.91,并将UM重新命名为UML(Unified Modeling Language)。
1996年,一些机构将UML作为其商业策略已日趋明显。UML的开发者得到了来自公众的正面反应,并倡议成立了UML成员协会,以完善、加强和促进UML的定义工作。当时的成员有DEC、HP、I-Logix、 Itellicorp、 IBM、ICON Computing、MCI Systemhouse、Microsoft、Oracle、Rational Software、TI以及Unisys。这一机构对UML 1.0(1997年1月)及UML 1.1(1997年11月17日)的定义和发布起了重要的促进作用。
UML是一种定义良好、易于表达、功能强大且普遍适用的建模语言。它溶入了软件工程领域的新思想、新方法和新技术。它的作用域不限于支持面向对象的分析与设计,还支持从需求分析开始的软件开发的全过程。
面向对象技术和UML的发展过程可用上图来表示,标准建模语言的出现是其重要成果。在美国,截止1996年10月,UML获得了工业界、科技界和应用界的广泛支持,已有700多个公司表示支持采用UML作为建模语言。1996年底,UML已稳占面向对象技术市场的85%,成为可视化建模语言事实上的工业标准。1997年11月17日,OMG采纳UML 1.1作为基于面向对象技术的标准建模语言。UML代表了面向对象方法的软件开发技术的发展方向,具有巨大的市场前景,也具有重大的经济价值和国防价值。
二. 标准建模语言UML的内容
首先,UML融合了Booch、OMT和OOSE方法中的基本概念,而且这些基本概念与其他面向对象技术中的基本概念大多相同,因而,UML必然成为这些方法以及其他方法的使用者乐于采用的一种简单一致的建模语言;其次,UML不仅仅是上述方法的简单汇合,而是在这些方法的基础上广泛征求意见,集众家之长,几经修改而完成的,UML扩展了现有方法的应用范围;第三,UML是标准的建模语言,而不是标准的开发过程。尽管UML的应用必然以系统的开发过程为背景,但由于不同的组织和不同的应用领域,需要采取不同的开发过程。
作为一种建模语言,UML的定义包括UML语义和UML表示法两个部分。
(1) UML语义 描述基于UML的精确元模型定义。元模型为UML的所有元素在语法和语义上提供了简单、一致、通用的定义性说明,使开发者能在语义上取得一致,消除了因人而异的最佳表达方法所造成的影响。此外UML还支持对元模型的扩展定义。
(2) UML表示法 定义UML符号的表示法,为开发者或开发工具使用这些图形符号和文本语法为系统建模提供了标准。这些图形符号和文字所表达的是应用级的模型,在语义上它是UML元模型的实例。
标准建模语言UML的重要内容可以由下列五类图(共9种图形)来定义:
?第一类是用例图,从用户角度描述系统功能,并指出各功能的操作者。
?第二类是静态图 (Static diagram),包括类图、对象图和包图。其中类图描述系统中类的静态结构。不仅定义系统中的类,表示类之间的联系如关联、依赖、聚合等,也包括类的内部结构(类的属性和操作)。类图描述的是一种静态关系,在系统的整个生命周期都是有效的。
对象图是类图的实例,几乎使用与类图完全相同的标识。他们的不同点在于对象图显示类的多个对象实例,而不是实际的类。一个对象图是类图的一个实例。由于对象存在生命周期,因此对象图只能在系统某一时间段存在。
包由包或类组成,表示包与包之间的关系。包图用于描述系统的分层结构。
?第三类是行为图(Behavior diagram),描述系统的动态模型和组成对象间的交互关系。其中状态图描述类的对象所有可能的状态以及事件发生时状态的转移条件。通常,状态图是对类图的补充。在实用上并不需要为所有的类画状态图,仅为那些有多个状态其行为受外界环境的影响并且发生改变的类画状态图。
而活动图描述满足用例要求所要进行的活动以及活动间的约束关系,有利于识别并行活动。
?第四类是交互图(Interactive diagram),描述对象间的交互关系。其中顺序图显示对象之间的动态合作关系,它强调对象之间消息发送的顺序,同时显示对象之间的交互;合作图描述对象间的协作关系,合作图跟顺序图相似,显示对象间的动态合作关系。除显示信息交换外,合作图还显示对象以及它们之间的关系。如果强调时间和顺序,则使用顺序图;如果强调上下级关系,则选择合作图。这两种图合称为交互图。
?第五类是实现图 ( Implementation diagram )。其中构件图描述代码部件的物理结构及各部件之间的依赖关系。一个部件可能是一个资源代码部件、一个二进制部件或一个可执行部件。它包含逻辑类或实现类的有关信息。部件图有助于分析和理解部件之间的相互影响程度。
配置图定义系统中软硬件的物理体系结构。它可以显示实际的计算机和设备(用节点表示)以及它们之间的连接关系,也可显示连接的类型及部件之间的依赖性。在节点内部,放置可执行部件和对象以显示节点跟可执行软件单元的对应关系。
从应用的角度看,当采用面向对象技术设计系统时,首先是描述需求;其次根据需求建立系统的静态模型,以构造系统的结构;第三步是描述系统的行为。其中在第一步与第二步中所建立的模型都是静态的,包括用例图、类图(包含包)、对象图、组件图和配置图等五个图形,是标准建模语言UML的静态建模机制。其中第三步中所建立的模型或者可以执行,或者表示执行时的时序状态或交互关系。它包括状态图、活动图、顺序图和合作图等四个图形,是标准建模语言UML的动态建模机制。因此,标准建模语言UML的主要内容也可以归纳为静态建模机制和动态建模机制两大类。
三. 标准建模语言UML的主要特点
UML的目标是以面向对象图的方式来描述任何类型的系统,具有很宽的应用领域。其中最常用的是建立软件系统的模型,但它同样可以用于描述非软件领域的系统,如机械系统、企业机构或业务过程,以及处理复杂数据的信息系统、具有实时要求的工业系统或工业过程等。总之,UML是一个通用的标准建模语言,可以对任何具有静态结构和动态行为的系统进行建模。
此外,UML适用于系统开发过程中从需求规格描述到系统完成后测试的不同阶段。在需求分析阶段,可以用用例来捕获用户需求。通过用例建模,描述对系统感兴趣的外部角色及其对系统(用例)的功能要求。分析阶段主要关心问题域中的主要概念(如抽象、类和对象等)和机制,需要识别这些类以及它们相互间的关系,并用UML类图来描述。为实现用例,类之间需要协作,这可以用UML动态模型来描述。在分析阶段,只对问题域的对象(现实世界的概念)建模,而不考虑定义软件系统中技术细节的类(如处理用户接口、数据库、通讯和并行性等问题的类)。这些技术细节将在设计阶段引入,因此设计阶段为构造阶段提供更详细的规格说明。
编程(构造)是一个独立的阶段,其任务是用面向对象编程语言将来自设计阶段的类转换成实际的代码。在用UML建立分析和设计模型时,应尽量避免考虑把模型转换成某种特定的编程语言。因为在早期阶段,模型仅仅是理解和分析系统结构的工具,过早考虑编码问题十分不利于建立简单正确的模型。
UML模型还可作为测试阶段的依据。系统通常需要经过单元测试、集成测试、系统测试和验收测试。不同的测试小组使用不同的UML图作为测试依据:单元测试使用类图和类规格说明;集成测试使用部件图和合作图;系统测试使用用例图来验证系统的行为;验收测试由用户进行,以验证系统测试的结果是否满足在分析阶段确定的需求。
总之,标准建模语言UML适用于以面向对象技术来描述任何类型的系统,而且适用于系统开发的不同阶段,从需求规格描述直至系统完成后的测试和维护。
五、标准建模语言UML的静态建模机制
任何建模语言都以静态建模机制为基础,标准建模语言UML也不例外。
UML的静态建模 机制包括用例图(Use case diagram)、类图(Class diagram)、对象图(Object diagram )、包(Package)、构件图(Component diagram)和配置图(Deployment diagram)。
1. 用例图
(1) 用例模型(Use case model) 长期以来,在面向对象开发和传统的软件开发中,人们根据典型的使用情景来了解需 求。
但是,这些使用情景是非正式的,虽然经常使用,却难以建立正式文挡。用例模型由I var Jacobson在开发AXE系统中首先使用,并加入由他所倡导的OOSE和Objectory方法中。
用例方法引起了面向对象领域的极大关注。自1994年Ivar Jacobson的著作出版后,面向 对象领域已广泛接纳了用例这一概念,并认为它是第二代面向对象技术的标志。
用例模型描述的是外部执行者(Actor)所理解的系统功能。用例模型用于需求分析阶 段,它的建立是系统开发者和用户反复讨论的结果,表明了开发者和用户对需求规格达成 的共识。
首先,它描述了待开发系统的功能需求;
其次,它将系统看作黑盒,从外部执行者 的角度来理解系统;
第三,它驱动了需求分析之后各阶段的开发工作,不仅在开发过程中保 证了系统所有功能的实现,而且被用于验证和检测所开发的系统,从而影响到开发工作的 各个阶段和 UML 的各个模型。
在UML中,一个用例模型由若干个用例图描述,用例图主要 元素是用例和执行者。
(2) 用例(use case) 从本质上讲,一个用例是用户与计算机之间的一次典型交互作用。
以字处理软件为例 ,"将某些正文置为黑体"和"创建一个索引"便是两个典型的用例。在UML中,用例被定义成 系统执行的一系列动作,动作执行的结果能被指定执行者察觉到。
在UML中,用例表示为一个椭圆。
图1显示了一个金融贸易系统的用例图。其中,"风险 分析","交易估价","进行交易","设置边界","超越边界的交易","评价贸易","更新帐目 "等都是用例的实例。
概括地说,用例有以下特点:
·用例捕获某些用户可见的需求,实现一个具体的用户目标。
·用例由执行者激活,并提供确切的值给执行者。
·用例可大可小,但它必须是对一个具体的用户目标实现的完整描述。
(3) 执行者(Actor) 执行者是指用户在系统中所扮演的角色。其图形化的表示是一个小人。
图1中有四个 执行者:贸易经理、营销人员、售货员和记帐系统。在某些组织中很可能有许多营销人员 ,但就该系统而言,他们均起着同一种作用,扮演着相同的角色,所以用一个执行者表示。
一个用户也可以扮演多种角色(执行者)。例如,一个高级营销人员既可以是贸易经理,也 可以是普通的营销人员;一个营销人员也可以是售货员。在处理执行者时,应考虑其作用 ,而不是人或工作名称,这一点是很重要的。
图1中,不带箭头的线段将执行者与用例连接到一起,表示两者之间交换信息,称之为 通信联系。执行者触发用例,并与用例进行信息交换。单个执行者可与多个用例联系;反 过来,一个用例可与多个执行者联系。对同一个用例而言,不同执行者有着不同的作用:他 们可以从用例中取值,也可以参与到用例中。
需要注意的是,尽管执行者在用例图中是用类似人的图形来表示的,但执行者未必是 人。例如,执行者也可以是一个外界系统,该外界系统可能需要从当前系统中获取信息,与 当前系统有进行交互。在图1中,我们可以看到,记帐系统是一个外界系统,它需要更新帐 目。
通过实践,我们发现执行者对提供用例是非常有用的。面对一个大系统,要列出用例 清单常常是十分困难。这时可先列出执行者清单,再对每个执行者列出它的用例,问题就 会变得容易很多。
(4) 使用和扩展(Use and Extend) 图1中除了包含执行者与用例之间的连接外,还有另外两种类型的连接,用以表示用例 之间的使用和扩展关系。使用和扩展是两种不同形式的继承关系。 当一个用例与另一个用例相似,但所做的动作多一些,就可以用到扩展关系。
例如图 1中,基本的用例是"进行交易"。 交易中可能一切都进行得很顺利,但也可能存在扰乱顺 利进行交易的因素。
其中之一便是超出某些边界值的情况。例如,贸易组织会对某个特定 客户规定最大贸易量,这时不能执行给定用例提供的常规动作,而要做些改动。我们可在 "进行交易"用例中做改动。但是,这将把该用例与一大堆特殊的判断和逻辑混杂在一起, 使正常的流程晦涩不堪。
图1中将常规的动作放在"进行交易"用例中,而将非常规的动作 放置于"超越边界的交易" 用例中,这便是扩展关系的实质。 当有一大块相似的动作存在于几个用例,又不想重复描述该动作时,就可以用到使用 关系。
例如,现实中风险分析和交易估价都需要评价贸易,为此可单独定义一个用例,即" 评价贸易",而"风险分析"和"交易估价"用例将使用它。 请注意扩展与使用之间的相似点和不同点。它们两个都意味着从几个用例中抽取那 些公共的行为并放入一个单独用例中,而这个用例被其他几个用例使用或扩展。
但使用和 扩展的目的是不同的。
(5) 用例模型的获取 几乎在任何情况下都会使用用例。用例用来获取需求,规划和控制项目。
用例的获取 是需求分析阶段的主要任务之一,而且是首先要做的工作。大部分用例将在项目的需求分 析阶段产生,并且随着工作的深入会发现更多的用例,这些都应及时增添到已有的用例集 中。
用例集中的每个用例都是一个潜在的需求。
a. 获取执行者 获取用例首先要找出系统的执行者。可以通过用户回答一些问题的答案来识别执行 者。
以下问题可供参考:
·谁使用系统的主要功能(主要使用者)。
·谁需要系统支持他们的日常工作。
·谁来维护、管理使系统正常工作(辅助使用者)。
·系统需要操纵哪些硬件。
·系统需要与哪些其它系统交互,包含其它计算机系统和其它应用程序。
·对系统产生的结果感兴趣的人或事物。
b. 获取用例 一旦获取了执行者,就可以对每个执行者提出问题以获取用例。以下问题可供参考:
·执行者要求系统提供哪些功能(执行者需要做什么)?
·执行者需要读、产生、删除、修改或存储的信息有哪些类型。
·必须提醒执行者的系统事件有哪些?或者执行者必须提醒系统的事件有哪些?怎样 把这些事件表示成用例中的功能?
·为了完整地描述用例,还需要知道执行者的某些典型功能能否被系统自动实现? 还有一些不针对具体执行者问题(即针对整个系统的问题):
·系统需要何种输入输出?输入从何处来?输出到何处?
·当前运行系统(也许是一些手工操作而不是计算机系统)的主要问题?
需要注意,最后两个问题并不是指没有执行者也可以有用例,只是获取用例时尚不知 道执行者是什么。
一个用例必须至少与一个执行者关联。还需要注意:不同的设计者对用 例的利用程度也不同。例如,Ivar Jacobson说,对一个十人年的项目,他需要二十个用例 。
而在一个相同规模的项目中,Martin Fowler则用了一百多个用例。我们认为:任何合适 的用例都可使用,确定用例的过程是对获取的用例进行提炼和归纳的过程,对一个十人年 的项目来说,二十个用例似乎太少,一百多个用例则嫌太多,需要保持二者间的相对均衡。
2. 类图、对象图和包 数千年以前,人类就已经开始采用分类的方法有效地简化复杂问题,帮助人们了解客 观世界。
在面向对象建模技术中,我们使用同样的方法将客观世界的实体映射为对象,并 归纳成一个个类。类(Class)、对象(Object)和它们之间的关联是面向对象技术中最基本 的元素。
对于一个想要描述的系统,其类模型和对象模型揭示了系统的结构。在UML中,类 和对象模型分别由类图和对象图表示。
类图技术是OO方法的核心。图1显示了一个金融保 险系统的类图。
(1) 类图 类图(Class Diagram)描述类和类之间的静态关系。与数据模型不同,它不仅显示了 信息的结构,同时还描述了系统的行为。类图是定义其它图的基础。
在类图的基础上,状 态图、合作图等进一步描述了系统其他方面的特性。
(2) 类和对象 对象(Object)与我们对客观世界的理解相关。我们通常用对象描述客观世界中某个 具体的实体。
所谓类(Class)是对一类具有相同特征的对象的描述。而对象是类的实例( Instance)。建立类模型时,我们应尽量与应用领域的概念保持一致,以使模型更符合客观 事实,易修改、易理解和易交流。
类描述一类对象的属性(Attribute)和行为(Behavior)。在UML中,类的可视化表示为 一个划分成三个格子的长方形(下面两个格子可省略)。
图1中,"客户"就是一个典型的类 。 类的获取和命名 最顶部的格子包含类的名字。
类的命名应尽量用应用领域中的术 语,应明确、无歧义,以利于开发人员与用户之间的相互理解和交流。
类的获取是一个依 赖于人的创造力的过程,必须与领域专家合作,对研究领域仔细地分析,抽象出领域中的概 念,定义其含义及相互关系,分析出系统类,并用领域中的术语为类命名。一般而言,类的 名字是名词。 类的属性 中间的格子包含类的属性,用以描述该类对象的共同特点。
该项可省略。
图1中"客户"类有"客户名"、"地址"等特性。属性的选取应考虑以下因素: *原则上来说,类的属性应能描述并区分每个特定的对象;
*只有系统感兴趣的特征才包含在类的属性中; *系统建模的目的也会影响到属性的选取。 根据图的详细程度,每条属性可以包括属性的可见性、属性名称、类型、缺省值和约 束特性。
UML规定类的属性的语法为: 可见性 属性名 : 类型 = 缺省值 {约束特性} 图1"客户"类中,"客户名"属性描述为"- 客户名 : 字符串 = 缺省客户名"。
可见性 "-"表示它是私有数据成员,其属性名为"客户名",类型为"字符串"类型,缺省值为"缺省客 户名",此处没有约束特性。
不同属性具有不同可见性。常用的可见性有Public、Private和Protected三种,在U ML中分别表示为"+"、"-"和"#"。
类型表示该属性的种类。它可以是基本数据类型,例如整数、实数、布尔型等,也可 以是用户自定义的类型。一般它由所涉及的程序设计语言确定。
约束特性则是用户对该属性性质一个约束的说明。例如"{只读}"说明该属性是只读 属性。 类的操作(Operation) 该项可省略。操作用于修改、检索类的属性或执行某些动作 。
操作通常也被称为功能,但是它们被约束在类的内部,只能作用到该类的对象上。操作 名、返回类型和参数表组成操作界面。
UML规定操作的语法为: 可见性 操作名 (参数表) : 返回类型 {约束特性} 在图1中,"客户"类中有"取客户地址"操作,其中" +"表示该操作是公有操作,调用时 需要参数"客户名",参数类型为字符串,返回类型也为字符串。 类图描述了类和类之间的静态关系。定义了类之后,就可以定义类之间的各种关系了 。
(3) 关联关系 关联(Association)表示两个类之间存在某种语义上的联系。例如,一个人为一家公 司工作,一家公司有许多办公室。我们就认为人和公司、公司和办公室之间存在某种语义 上的联系。在分析设计的类图模型中,则在对应人类和公司类、公司类和办公室类之间建 立关联关系。
在图1中最上部存在一个"属于"/"签定"关联:每个"保险单"属于一个"客户",而"客户 "可以签定多个"保险单"。除了这个关联外,图1中还有另外两个关联,分别表示每个"保险 单"包含若干个"保险单上的项目",而每个"保险单上的项目"涉及单一的"保险类别"。 关联的方向 关联可以有方向,表示该关联单方向被使用。关联上加上箭头表示方向 ,在UML中称为导航(Navigability)。我们将只在一个方向上存在导航表示的关联,称作单 向关联 ( Uni-directional Association ),在两个方向上都有导航表示的关联,称作双 向关联 ( Bi-directional Association )。
图1中,"保险单"到"保险单上的项目"是单向 关联。UML规定,不带箭头的关联可以意味着未知、未确定或者该关联是双向关联三种选 择,因此,在图中应明确使用其中的一种选择。 关联的命名 既然关联可以是双向的,最复杂的命名方法是每个方向上给出一个名字 ,这样的关联有两个名字,可以用小黑三角表示名字的方向(见图1中最上部的"属于"/"签 定"关联)。为关联命名有几种方法,其原则是该命名是否有助于理解该模型。 角色 关联两头的类以某种角色参与关联。
例如图2中,"公司"以"雇主"的角色,"人 "以"雇员"的角色参与的"工作合同"关联。"雇主"和"雇员"称为角色名。如果在关联上没 有标出角色名,则隐含地用类的名称作为角色名。角色还具有多重性(Multiplicity),表 示可以有多少个对象参与该关联。在图2中,雇主(公司)可以雇佣(签工作合同)多个雇员 ,表示为"*"; 雇员只能与一家雇主签定工作合同,表示为"1"。
多重性表示参与对象的数 目的上下界限制。"*"代表0~∞,即一个客户可以没有保险单,也可以有任意多的保险单 。
"1"是1..1的简写,即任何一个保险单仅来自于一个客户,可以用一个单个数字表示,也 可以用范围或者是数字和范围不连续的组合表示。 关联类 一个关联可能要记录一些信息,可以引入一个关联类来记录。
图3是在图2的 基础上引入了关联类。
关联类通过一根虚线与关联连接。
图4是实现上述目标的另外一种 方法,就是使雇用关系成为一个正式的类。
聚集和组成 聚集(Aggregation)是一种特殊形式的关联。聚集表示类之间的关系是 整体与部分的关系。一辆轿车包含四个车轮、一个方向盘、一个发动机和一个底盘,这是 聚集的一个例子。在需求分析中,"包含"、"组成"、"分为……部分"等经常设计成聚集关 系。聚集可以进一步划分成共享聚集(Shared Aggregation)和组成。
例如,课题组包含许 多成员,但是每个成员又可以是另一个课题组的成员,即部分可以参加多个整体,我们称之 为共享聚集。
另一种情况是整体拥有各部分,部分与整体共存,如整体不存在了,部分也会 随之消失,这称为组成(Composition)。例如,我们打开一个视窗口,它就由标题、外框和 显示区所组成。一旦消亡则各部分同时消失。在UML中,聚集表示为空心菱形,组成表示为 实心菱形。
需要注意的是,一些面向对象大师对聚集的定义并不一样。大家应注意其他面向对象 方法与UML中所定义的聚集的差别。
(4) 继承关系 人们将具有共同特性的元素抽象成类别,并通过增加其内涵而进一步分类。
例如,动 物可分为飞鸟和走兽,人可分为男人和女人。在面向对象方法中将前者称为一般元素、基 类元素或父元素,将后者称为特殊元素或子元素。继承(Generalization)定义了一般元素 和特殊元素之间的分类关系。在UML中,继承表示为一头为空心三角形的连线。如图1中, 将客户进一步分类成个体客户和团体客户,使用的就是继承关系。 在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)(见图5)。
不仅是类,任何模型元素都运用包的机制。如果没有任何启发性原则来指导类的分组 ,分组方法就是任意的。
在UML中,最有用的和强调最多的启发性原则就是依赖。包图主要 显示类的包以及这些包之间的依赖关系。有时还显示包和包之间的继承关系和组成关系 。
包的内容 在图5中,"系统内部"包由"保险单"包和"客户"包组成。这里称"保险单" 包和"客户"包为"系统内部"包的内容。当不需要显示包的内容时,包的名字放入主方框内 ,否则包的名字放入左上角的小方框中,而将内容放入主方框内。包的内容可以是类的列 表,也可以是另一个包图,还可以是一个类图。
包的依赖和继承 图5中"保险单填写界面"包依赖于"保险单"包;整个"系统内部"包 依赖于"数据库界面"包。
可以使用继承中通用和特例的概念来说明通用包和专用包之间 的关系。例如,专用包必须符合通用包的界面,与类继承关系类似。通过"数据库界面"包 ,"系统内部"包既能够使用Oracle的界面也可使用Sybase的界面。通用包可标记为 {abs tract},表示该包只是定义了一个界面,具体实现则由专用包来完成。
(10) 其他模型元素和表示机制 类图中用到的模型元素和表示机制较为丰富,由于篇幅的限制,这里不能一一介绍。
主要还有以下模型符号和概念:类别模板(Stereotype)、界面(Interface)、参数化类(P arameterized Class)也称模板类(Template)、限定关联(Qualified Association)、多 维关联(N-ary Association)、多维链(N-ary Link)、派生(Derived)、类型(Type)和注 释(Note)等。
(11) 使用类图的几个建议 类图几乎是所有OO方法的支柱。采用标准建模语言UML进行建模时,必须对UML类图引 入的各种要素有清晰的理解。以下对使用类图进行建模提出几点建议:
*不要试图使用所有的符号。从简单的开始,例如,类、关联、属性和继承等概念。在 UML中,有些符号仅用于特殊的场合和方法中,只有当需要时才去使用。
*根据项目开发的不同阶段,用正确的观点来画类图。如果处于分析阶段,应画概念层 类图;当开始着手软件设计时,应画说明层类图;当考察某个特定的实现技术时,则应画实 现层类图。
*不要为每个事物都画一个模型,应该把精力放在关键的领域。最好只画几张较为关 键的图,经常使用并不断更新修改。 使用类图的最大危险是过早地陷入实现细节。为了避免这一危险,应该将重点放在概 念层和说明层。如果已经遇到了一些麻烦,可以从以下几个方面来反思你的模型。
*模型是否真实地反映了研究领域的实际。 *模型和模型中的元素是否有清楚的目的和职责(在面向对象方法中,系统功能最终是 分配到每个类的操作上实现的,这个机制叫职责分配)。
*模型和模型元素的大小是否适中。过于复杂的模型和模型元素是很难生存的,应将 其分解成几个相互合作的部分。
(12) 术语比较 下表列出了最常用的四种UML术语,并与其他方法学中相对应的术语进行比较,以帮助 读者了解UML与其他建模语言的异同。
3. 构件图和配置图 构件图(Component diagram)和配置图(Deployment diagram)显示系统实现时的一些 特性,包括源代码的静态结构和运行时刻的实现结构。构件图显示代码本身的结构,配置 图显示系统运行时刻的结构。
(1) 构件图 构件图显示软件构件之间的依赖关系。一般来说,软件构件就是一个实 际文件,可以是源代码文件、二进制代码文件和可执行文件等。可以用来显示编译、链接 或执行时构件之间的依赖关系。
(2) 配置图 配置图描述系统硬件的物理拓扑结构以及在此结构上执行的软件。配置 图可以显示计算结点的拓扑结构和通信路径、结点上运行的软件构件、软件构件包含的 逻辑单元(对象、类)等。配置图常常用于帮助理解分布式系统。
(3) 结点和连接 结点(Node)代表一个物理设备以及其上运行的软件系统,如一台U nix主机、一个PC终端、一台打印机、一个传感器等。如图1所示,"客户端PC"和"保险后 台服务器"就是两个结点。结点表示为一个立方体,结点名放在左上角。 结点之间的连线表示系统之间进行交互的通信路径,在UML中被称为连接(Connectio n)。通信类型则放在连接旁边的"《》"之间,表示所用的通信协议或网络类型。
(4) 构件和界面 在配置图中,构件代表可执行的物理代码模块,如一个可执行程序 。逻辑上它可以与类图中的包或类对应。因此,配置图中显示运行时各个包或类在结点中 的分布情况。如在图1中,"保险后台服务器" 结点中包含"保险系统"、"保险对象数据库 "和"保险系统配置"3个构件。 在面向对象方法中,类和构件等元素并不是所有的属性和操作都对外可见。
它们对外 提供了可见操作和属性,称之为类和构件的界面。界面可以表示为一头是小园圈的直线。
图1中,"保险系统"构件提供了一个"配置"界面。配置图中还显示了构件之间的依赖关系 ,"保险系统配置"构件依赖于这个"配置"界面。
(5) 对象(Object) 一个面向对象软件系统中可以运行很多对象。由于构件可以看 作与包或类对应的物理代码模块,因此,构件中应包含一些运行的对象。配置图中的对象 与对象图中的对象表示法一样。
图1中,"保险系统配置"构件包含"配置保险政策"和"配置 用户"两个对象。
标准建模语言UML的静态建模机制是采用UML进行建模的基础。我们认为,熟练掌握基 本概念、区分不同抽象层次以及在实践中灵活运用,是三条最值得注意的基本原则。
六、标准建模语言UML的动态建模机制
1. 消息 在面向对象技术中,对象间的交互是通过对象间消息的传递来完成的。
在UML的四个 动态模型中均用到消息这个概念。通常,当一个对象调用另一个对象中的操作时,即完成 了一次消息传递。
当操作执行后,控制便返回到调用者。
对象通过相互间的通信(消息传 递)进行合作,并在其生命周期中根据通信的结果不断改变自身的状态。
在UML中,消息的图形表示是用带有箭头的线段将消息的发送者和接收者联系起来,箭 头的类型表示消息的类型,如图2所示。
UML定义的消息类型有三种:
简单消息(Simple Message) 表示简单的控制流。用于描述控制如何在对象间进行传 递,而不考虑通信的细节。
同步消息(Synchronous Message) 表示嵌套的控制流。
操作的调用是一种典型的同 步消息。
调用者发出消息后必须等待消息返回,只有当处理消息的操作执行完毕后,调用 者才可继续执行自己的操作。
异步消息(Asynchronous Message) 表示异步控制流。
当调用者发出消息后不用等待 消息的返回即可继续执行自己的操作。
异步消息主要用于描述实时系统中的并发行为。
2. 状态图 状态图(State Diagram)用来描述一个特定对象的所有可能状态及其引起状态转移的 事件。大多数面向对象技术都用状态图表示单个对象在其生命周期中的行为。一个状态 图包括一系列的状态以及状态之间的转移。
(1) 状态 所有对象都具有状态,状态是对象执行了一系列活动的结果。当某个事件 发生后,对象的状态将发生变化。
状态图中定义的状态有:初态、终态、中间状态、复合 状态。其中,初态是状态图的起始点,而终态则是状态图的终点。一个状态图只能有一个 初态,而终态则可以有多个。
中间状态包括两个区域:名字域和内部转移域,如图3所示。图中内部转移域是可选的 ,其中所列的动作将在对象处于该状态时执行,且该动作的执行并不改变对象的状态。
一个状态可以进一步地细化为多个子状态,我们将可以进一步细化的状态称作复合状 态。子状态之间有"或关系"和"与关系"两种关系。
或关系(如 图4)说明在某一时刻仅可 到达一个子状态。
例如,一个处于行驶状态的汽车,在"行驶"这个复合状态中有向前和向 后两个不同的子状态,在某一时刻汽车要么向前,要么向后。与关系( 如图5)说明复合状 态中在某一时刻可同时到达多个子状态(称为并发子状态)。具有并发子状态的状态图称 为并发状态图。
(2) 转移 状态图中状态之间带箭头的连线被称为转移。状态的变迁通常是由事件 触发的,此时应在转移上标出触发转移的事件表达式。如果转移上未标明事件,则表示在 源状态的内部活动执行完毕后自动触发转移。
3. 顺序图 顺序图(Sequence Diagram)用来描述对象之间动态的交互关系,着重体现对象间消息 传递的时间顺序。
顺序图存在两个轴:水平轴表示不同的对象,垂直轴表示时间。
顺序图 中的对象用一个带有垂直虚线的矩形框表示,并标有对象名和类名。垂直虚线是对象的生 命线,用于表示在某段时间内对象是存在的。对象间的通信通过在对象的生命线间画消息 来表示。消息的箭头指明消息的类型。
顺序图中的消息可以是信号(Signal)、操作调用或类似于C++中的RPC(RemoteProce dure Calls)和Java中的RMI(Remote Method Invocation)。当收到消息时,接收对象立即 开始执行活动,即对象被激活了。
通过在对象生命线上显示一个细长矩形框来表示激活。 消息可以用消息名及参数来标识。
消息也可带有顺序号,但较少使用。消息还可带有 条件表达式,表示分支或决定是否发送消息。如果用于表示分支,则每个分支是相互排斥 的,即在某一时刻仅可发送分支中的一个消息。
在顺序图的左边可以有说明信息,用于说明消息发送的时刻、描述动作的执行情况以 及约束信息等。一个典型的例子就是用于说明一个消息是重复发送的。
另外,可以定义两 个消息间的时间限制。
一个对象可以通过发送消息来创建另一个对象,当一个对象被删除或自我删除时,该 对象用"X"标识。
另外,在很多算法中,递归是一种很重要的技术。当一个操作直接或间接调用自身时 ,即发生了递归。
产生递归的消息总是同步消息,返回消息应是一个简单消息。
4. 合作图 合作图(Collaboration Diagram)用于描述相互合作的对象间的交互关系和链接关系 。
虽然顺序图和合作图都用来描述对象间的交互关系,但侧重点不一样。顺序图着重体现 交互的时间顺序,合作图则着重体现交互对象间的静态链接关系。
合作图中对象的外观与顺序图中的一样。如果一个对象在消息的交互中被创建,则可 在对象名称之后标以{new}。
类似地,如果一个对象在交互期间被删除,则可在对象名称之 后标以{destroy}。对象间的链接关系类似于类图中的联系(但无多重性标志)。通过在对 象间的链接上标志带有消息串的消息(简单、异步或同步消息)来表达对象间的消息传递 。
(1) 链接 链接用于表示对象间的各种关系,包括组成关系的链接(Composition Li nk)、聚集关系的链接(Aggregation Link)、限定关系的链接(Qualified Link)以及导航 链接(Navigation Link)。
各种链接关系与类图中的定义相同,在链接的端点位置可以显 示对象的角色名和模板信息。
(2) 消息流 在合作图的链接线上,可以用带有消息串的消息来描述对象间的交互。 消息的箭头指明消息的流动方向。
消息串说明要发送的消息、消息的参数、消息的返回 值以及消息的序列号等信息。
标准建模语言UML的主要特点可以归结为三点:
(1) UML统一了Booch、OMT和OOSE等方法中的基本概念。
(2) UML还吸取了面向对象技术领域中其他流派的长处,其中也包括非OO方法的影响。UML符号表示考虑了各种方法的图形表示,删掉了大量易引起混乱的、多余的和极少使用的符号,也添加了一些新符号。因此,在UML中汇入了面向对象领域中很多人的思想。这些思想并不是UML的开发者们发明的,而是开发者们依据最优秀的OO方法和丰富的计算机科学实践经验综合提炼而成的。
(3)UML在演变过程中还提出了一些新的概念。在UML标准中新加了模板(Stereotypes)、职责(Responsibilities)、扩展机制(Extensibility mechanisms)、线程(Threads)、过程(Processes)、分布式(Distribution)、并发(Concurrency)、模式(Patterns)、合作(Collaborations)、活动图(Activity diagram)等新概念,并清晰地区分类型(Type)、类(Class)和实例(Instance)、细化(Refinement)、接口(Interfaces)和组件(Components)等概念。
因此可以认为,UML是一种先进实用的标准建模语言,但其中某些概念尚待实践来验证,UML也必然存在一个进化过程。
四. 标准建模语言UML的应用领域
UML的组成 |