UML简明教程

20 世纪80 年代,随着面向对象技术成为研究的热点,先后出现了几十种面向对象的软件开发方法。其中,Booch、OMT 和OOSE等方法得到了广泛的认可。然而,采用不同方法进行建模不利于开发者之间的交流。而UML则统一了Booch、OMT 和OOSE 的表示方法,而且对其作了进一步的发展。1997 年,UML 被国际对象组织OMG采纳为面向对象的建模语言的国际标准,它溶入了软件工程领域的新思想、新方法和新技术。UML不限于支持面向对象的分析与设计,还支持从需求分析开始的软件开发的全过程。数年来,UML凭借其简洁明晰的表达方式、超凡脱俗的表达能力,一路杀将出来,为业界所广泛认同!目前,在多数大型企业的正规化开发流程中,开发人员普遍使用UML进行模型的建立。作为一名软件开发人员,我们必须学会UML。因为UML就是那个统一的"文字",统一的"度"、"量"、"衡",不理解UML,作为软件设计统一王国的国民,将是艰难而痛苦的。

  作曲家会将其脑袋中的旋律谱成乐曲,建筑师会将其设计的建筑物画成蓝图,这些乐曲、蓝图就是模型(Model),而建构这些模型的过程就称为建模(Modeling)。软件开发如同音乐谱曲及建筑设计,其过程中也必须将需求、分析、设计、实现、布署等各项工作流程的构想与结果予以呈现,这就是软件系统的建模。

  那么为什么要建模呢?经典答案是:建立大厦和建立狗窝的区别是建设狗窝不需要设计,要生产合格的软件就要有一套关于体系结构、过程和工具的规范。

  OMG官方发布的UML的当前最高版本为2.0,可以从http://www.uml.org/上下载。

  UML由图和元模型组成,图是语法,元模型是语义。UML主要包括三个基本构造块:事物(Things)、关系(Relationships)和图(Diagrams)。本次连载我们将对UML的这些基本组成部分及UML工具和应用进行介绍,使读者对UML形成初步的整体印象。在其后的几次连载里,再以数个实例对这些内容逐步展开。

  1.1 UML的基本构造块

  1.1.1事物

  事物是是实体抽象化的最终结果,是模型中的基本成员,UML中包含结构事物、行为事物、分组事物和注释事物。

  (1)结构事物(Structural things)

  结构事物是模型中的静态部分,用以呈现概念或实体的表现元素,是软件建模中最常见的元素,共有以下七种:

  类(Class):类是指具有相同属性、方法、关系和语义的对象的集合;

  接口(Interface):接口是指类或组件所提供的服务(操作),描述了类或组件对外可见的动作;

  协作(Collaboration):协作描述合作完成某个特定任务的一组类及其关联的集合,用于对使用情形的实现建模;

  用例(Use Case):用例定义了执行者(在系统外部和系统交互的人)和被考虑的系统之间的交互来实现的一个业务目标;

  活动类(Active Class):活动类的对象有一个或多个进程或线程。活动类和类很相象,只是它的对象代表的元素的行为和其他的元素是同时存在的;

  组件(Component):组件是物理的、可替换的部分,包含接口的集合,例如COM+ 、JAVA BEANS等;

  结点(Node):结点是系统在运行时存在的物理元素,代表一个可计算的资源,通常占用一些内存和具有处理能力。

  (2)行为事物(Behavioral things)

  行为事物指的是UML模型中的动态部分,代表语句里的"动词",表示模型里随着时空不断变化的部分,包含两类:

  交互(ineraction):交互是由一组对象之间在特定上下文中,为达到特定的目的而进行的一系列消息交换而组成的动作;

  状态机(state machine):状态机由一系列对象的状态组成。

  (3)分组事物(Grouping things)

  可以把分组事物看成是一个"盒子",模型可以在其中被分解。目前只有一种分组事物,即包(package)。结构事物、动作事物甚至分组事物都有可能放在一个包中。包纯粹是概念上的,只存在于开发阶段,而组件在运行时存在。

  (4)注释事物(Annotational things)

  注释事物是UML模型的解释部分。

  1.1.2关系

  关系是将事物联系在一起的方式,UML中定义了四种关系:

  (1)依赖(Dependencies):两个事物之间的语义关系,其中一个事物发生变化会影响另一个事物的语义;

  (2)关联(Association):一种描述一组对象之间连接的结构关系,如聚合关系(描述了整体和部分间的结构关系);

  (3)泛化(Generalization):一种一般化-特殊化的关系;

  (4)实现(Realization) :类之间的语义关系,其中的一个类指定了由另一个类保证执行的契约。

  1.1.3图

  图是事物集合的分类,UML中包含多种图:

  (1)类图(Class Diagram):类图描述系统所包含的类、类的内部结构及类之间的关系;

  (2)对象图(Object Diagram):对象图是类图的一个具体实例;

  (3)包图(Package Diagram):包图表明包及其之间的依赖类图;

  (4)组件图(Compoment Diagram,也称构件图):组件图描述代码部件的物理结构以及各部件之间的依赖关系;

  (5)部署图(Deployment Diagram):部署图定义系统中软硬件的物理体系结构;

  (6)用例图(Usecase Diagram):用例图从用户的角度出发描述系统的功能、需求,展示系统外部的各类角色与系统内部的各种用例之间的关系;

  (7)顺序图(Sequence Diagram):顺序图表示对象之间动态合作的关系;

  (8)协作图(Collaboration Diagram):合作图描述对象之间的协作关系;

  (9)状态图(Statechart Diagram):状态图描述一类对象的所有可能的状态以及事件发生时状态的转移条件;

  (10)活动图(Activity Diagram):活动图描述系统中各种活动的执行顺序。

  上述十种图可归纳为五类,如表1.1。

  表1.1 UML图分类

类型 包含
静态图 类图、对象图、包图
行为图 状态图、活动图
用例图 用例图
交互图 顺序图、协作图
实现图 组件图、部署图

目前,在的内地版《神雕侠侣》中,杨过和小龙女有一份不为人知的默契与浪漫,那就是他们所绘制的并肩小人图。这样的小人图,是UML用例图的一部分,被称为参与者。

  2.1 用例与用例图

  用例是需求分析中最重要的概念,需求表征了一个系统的设计特性、特征和行为,描述一个系统的需求意味着描述了建立在该系统外部的事物与系统之间的契约,契约上声明了期望系统做什么。

  需求获取(Requirement Elicitation) 是需求工程的主体,其主要工作是建立待开发系统的模型,而用例就是用于建立这种模型的良好方法。用例最初由Ivar Jackboson博士提出,后被综合到UML规范之中,成为需求表述的标准化体系。前文已经提到,整个RUP流程都是"用例驱动"的,各种类型的开发活动包括项目管理、分析、设计、测试、实现等以用例为主要输入工件,用例模型奠定了整个系统软件开发的基础,用例被认作第二代面向对象技术的标志,可见其重要性非同一般。

  我们先来给出一个具体而简单的用例图,即"图书管理系统"用例图,如图2.1。在用例图中主要涉及到参与者(又称角色、执行者)、用例以及二者之间的通讯关联。

UML简明教程
图2.1 图书管理系统用例图

   参与者

  参与者是与系统、子系统或类发生交互的外部用户、进程或其他系统。参与者可以是人、另一个计算机系统或一些可运行的进程。在图2.1中,"读者"和"管理员"即为参与者。

  参与者之间可以存在泛化关系,例如,在图2.1所示图书馆管理系统用例图中,可以认为"读者"是"学生读者"和"教师读者"的泛化,而"学生读者"还可以具体化为"本科生读者"和"研究生读者";同样,"图书管理人员"也是"采购员"、"编目员"及"借阅人员"的泛化。图2.2表示出了参与者之间的泛化关系。

UML简明教程
图2.2 参与者泛化关系

   用例

  用例是外部可见的一个系统功能,这些功能由系统所提供,并通过与参与者之间消息的交换来表达。用例的用途是在不揭示系统内部构造的情况下定义行为序列,它把系统当作一个黑箱,表达整个系统对外部用户可见的行为。

  鉴于用例的特点,用例一般被命名为一个能够说明目标的动名词组。如图2.1中的"借书"、"还书"和"管理图书"皆为动名词组。

  用例之间也可以存在包含、扩展和泛化等关系:

  (1)包含关系:用例可以简单地包含其他用例具有的行为,并把它所包含的用例行为做为自身行为的一部分,这被称作包含关系。

  (2)扩展关系:扩展关系是从扩展用例到基本用例的关系,它说明为扩展用例定义的行为如何插入到为基本用例定义的行为中。它是以隐含形式插入的,也就是说,扩展用例并不在基本用例中显示。在以下几种情况下,可使用扩展用例:

  a.表明用例的某一部分是可选的系统行为(这样,您就可以将模型中的可选行为和必选行为分开);

  b.表明只在特定条件(如例外条件)下才执行的分支流;

  c.表明可能有一组行为段,其中的一个或多个段可以在基本用例中的扩展点处插入。所插入的行为段和插入的顺序取决于在执行基本用例时与主角进行的交互。

  图2.3给出了一个扩展关系的例子,在还书的过程中,只有在例外条件(读者遗失书籍)的情况下,才会执行赔偿遗失书籍的分支流。

UML简明教程
图2.3用例扩展关系

  (3)泛化关系:用例可以被特别列举为一个或多个子用例,这被称做用例泛化。当父用例能够被使用时,任何子用例也可以被使用。如在图2.4中,订票是电话订票和网上订票的抽象。

UML简明教程
图2.4用例泛化关系

通讯关联

  通讯关联用于表示参与者和用例之间的对应关系,它表示参与者使用了系统中的哪些用例(或者说系统所提供的用例被哪些参与者使用)。

  通讯关联以箭头或实线表示。若使用箭头,箭头所指方将是对话的被动接受者;如果不强调对话中的主动与被动关系,则可以使用不带箭头的关联实线。

  2.2建立用例模型

  知道了用例与用例图的概念,我们还需要懂得怎样建立用例模型,即怎样找出参与者、用例以及定义用例的过程。一般来说,建立用例模型的步骤为:

  (1)确定谁会直接使用该系统,即参与者(Actor),为了发现参与者,我们可以尝试问如下问题:

  a. 谁/什么使用系统?

  b. 谁/什么从系统获得信息?

  c. 谁/什么向系统提供信息?

  d. 谁/什么支持、维护系统?

  e. 哪些其它系统使用此系统?

  f. 公司的哪个部门使用系统?

  …

  (2)选取其中一个参与者;

  (3)定义该参与者希望系统做什么,参与者希望系统做的每件事成为一个用例,为了发现用例,我们可以尝试问如下问题:

  a. 为什么该参与者想要使用此系统?

  b. 该参与者是否要创建、保存、更改、移动或读取系统的数据?如果是,为什么?

  c. 该参与者是否要通知系统外部事件或变化?

  d. 该参与者是否需要知道系统内部的特定事件?

  …

  (4)对每件事来说,何时参与者会使用系统,通常会发生什么,这就是用例的基本过程;

  (5)描述该用例的基本过程;

  (6)考虑一些可变情况,把他们创建为扩展用例;

  (7)复审不同用例的描述,找出其中的相同点,抽出相同点作为共同的用例;

  (8)重复步骤2-7找出每一个用例。

  参与者检查的参考标准如下:

  (1)是否您已找到所有的参与者?也就是说,是否您已经对系统环境中的所有参与者都进行了说明和建模?

  (2)每个参与者是否至少涉及到一个用例?

  (3)您能否列出至少两名可以作为特定参与者的人员?

  (4)是否有参与者担任与系统相关的相似参与者?如果有,您应该将他们合并到一个参与者中。

  用例检查的参考标准如下:

  (1)用例模型的简介部分简明清晰地概述此系统的目的和功能;

  (2)所有的用例已确定,这些用例共同说明所有的必要行为;

  (3)所有的功能性需求都至少映射到一个用例;

  (4)该用例模型不包含多余的行为,所有的用例都可回溯到某个功能性需求来证明其合理性。

  用例图从总体上大致描述了系统所能提供的各种服务,让我们对于系统的功能有一个总体的认识,仅此还是不够的,我们还需要描述每一个用例的详细信息,即用例规约。用例模型正是由用例图和每一个用例的详细描述――用例规约所组成的。RUP中提供了用例规约的模板,包含以下内容:

  (1)简要说明 (Brief Description):简要介绍该用例的作用和目的;

  (2)事件流 (Flow of Event):包括基本流和备选流,事件流应该表示出所有的场景;

  (3)用例场景 (Use-Case Scenario) :包括成功场景和失败场景,场景主要是由基本流和备选流组合而成的;

  (4)特殊需求 (Special Requirement):描述与该用例相关的非功能性需求(包括性能、可靠性、可用性和可扩展性等)和设计约束(所使用的操作系统、开发工具等);

  (5)前置条件 (Pre-Condition):执行用例之前系统必须所处的状态;

  (6)后置条件 (Post-Condition):用例执行完毕后系统可能处于的一组状态。

  用例规约基本上是用文本方式来表述的,为了更加清晰地描述事件流,也可以选择使用状态图、活动图或序列图来辅助说明(状态图有助于描述与状态相关的系统行为,活动图有助于描述复杂的决策流程,序列图适合于描述基于时间顺序的消息传递)。另外,只要对简洁明了地表达用例有帮助,我们就可以在用例中任意粘贴用户界面、流程的图形化显示方式及其他图形。

类是一种对本质相同事物的抽象,人类软件开发技术的发展历史,就是还事物以本源的历史,开发技术、名词越来越接近世界的真实,“面向对象”、“类”就是这样的产物。

  3.1类图

  在UML中,类图显示了一组类、接口、协作以及它们之间的关系。在UML的静态机制中类图是一个重点,它不但为设计人员所关心,更为实现人员所关注,建模工具也主要依据类图来产生代码(正向)工程。因此,类图在UML的各种图中占据了相当重要的地位。

  类

在类图中类用矩形框来表示,它的属性和操作分别列在分格中,若不需要表达详细信息时,分格可以省略。一个类可能出现在好几个图中。同一个类的属性和操作只在一种图中列出,在其他图中可省略。图3.1给出Student类和MFC中的CObject类。


图3.1类的表示

  类间关系

  在类图中,除了需要描述单独的类的名称、属性和操作外,我们还需要描述类之间的联系,因为没有类是单独存在的,它们通常需要和别的类协作,创造比单独工作更大的语义。在UML类图中,关系用类框之间的连线来表示,连线上和连线端头处的不同修饰符表示不同的关系。类之间的关系有继承(泛化)、关联、聚合和组合。

  (1)继承:指的是一个类(称为子类)继承另外的一个类(称为基类)的功能,并增加它自己的新功能的能力,继承是类与类之间最常见的关系。类图中继承的表示方法是从子类拉出一条闭合的、单键头(或三角形)的实线指向基类。例如,图3.2给出了MFC中CObject类和菜单类CMenu的继承关系。

UML简明教程
图3.2 类的继承

  类的继承在C++中呈现为:

  class B { }
  class A : public B{ }

  (2)关联:指的是模型元素之间的一种语义联系,是类之间的一种很弱的联系。关联可以有方向,可以是单向关联,也可以是双向关联。可以给关联加上关联名来描述关联的作用。关联两端的类也可以以某种角色参与关联,角色可以具有多重性,表示可以有多少个对象参与关联。可以通过关联类进一步描述关联的属性、操作以及其他信息。关联类通过一条虚线与关联连接。对于关联可以加上一些约束,以加强关联的含义。
 
  关联在C++中呈现为:

  class A{...}
  class B{ ...}
  A::Function1(B &b) //或A::Function1(B b) //或A::Function1(B *b)

  即一个类作为另一个类方法的参数。

  (3)聚合:指的是整体与部分的关系。通常在定义一个整体类后,再去分析这个整体类的组成结构。从而找出一些组成类,该整体类和组成类之间就形成了聚合关系。例如一个航母编队包括海空母舰、驱护舰艇、舰载飞机及核动力攻击潜艇等。需求描述中“包含”、“组成”、“分为…部分”等词常意味着聚合关系。

UML简明教程
图3.3 类的聚合

(4)组合:也表示类之间整体和部分的关系,但是组合关系中部分和整体具有统一的生存期。一旦整体对象不存在,部分对象也将不存在。部分对象与整体对象之间具有共生死的关系。

  聚合和组合的区别在于:聚合关系是“has-a”关系,组合关系是“contains-a”关系;聚合关系表示整体与部分的关系比较弱,而组合比较强;聚合关系中代表部分事物的对象与代表聚合事物的对象的生存期无关,一旦删除了聚合对象不一定就删除了代表部分事物的对象。组合中一旦删除了组合对象,同时也就删除了代表部分事物的对象。

  我们用浅显的例子来说明聚合和组合的区别。“国破家亡”,国灭了,家自然也没有了,“国”和“家”显然也是组合关系。而相反的,计算机和它的外设之间就是聚合关系,因为它们之间的关系相对松散,计算机没了,外设还可以独立存在,还可以接在别的计算机上。在聚合关系中,部分可以独立于聚合而存在,部分的所有权也可以由几个聚合来共享,比如打印机就可以在办公室内被广大同事共用。

  在C++语言中,从实现的角度讲,聚合可以表示为:

  class A {...}
  class B { A* a; .....}

  即类B包含类A的指针;

  而组合可表示为:

  class A{...}
  class B{ A a; ...}

  即类B包含类A的对象。

  准确的UML类图中用空心和实心菱形对聚合和组合进行了区分。


图3.4 聚合和组合

点击放大此图片
图3.5 银行管理系统类图

  图3.5给出了一个典型的银行管理系统的类图,基本上一看就懂:

  银行类聚合了账号库(AccountSet)、客户库(EmployeeSet)和员工库(EmployeeSet);

  账号库中包含了n个账号(Account)、客户库中包含了n个客户(Employee),员工库包含了n个员工(Employee);

  员工类和客户类都继承自人(Person)类,而员工类中又有一种特殊的员工,即员工管理者类(EmployeeAdmin);

  账号类和客户类之间体现出一种关联关系;

  单独的元素PersonSex定义了枚举类,其中包括Male和Female两种性别。

  我们再给出一个类图实例(图3.6),它来源于软件无线电SCA(软件通讯架构)标准。软件无线电技术是目前电信产品、军用电台中研究的大热门,在其定义的SCA体系中,核心框架即以类图的形式呈现,它定义了应用程序基本框架和标准控制服务接口。

  实际上,软件无线电核心框架即由类以及类之间的继承、关联和聚合关系组成。

UML简明教程
图3.6 软件无线电核心框架

  接下来,我们给出建立类图的步骤:

  (1)研究分析问题领域确定系统需求;

  类的识别是一个需要大量技巧的工作,寻找类的一些技巧包括:名词识别法;根据用例描述确定类;使用CRC分析法;根据边界类、控制类、实体类的划分来帮助分析系统中的类;参考设计模式确定类;对领域进行分析或利用已有领域分析结果得到类;利用RUP中如何在分析和设计中寻找类的步骤。

  (2)确定类,明确类的含义和职责、确定属性和操作;

  (3)确定类之间的关系。

   3.2对象图

  对象图显示某时刻对象和对象之间的关系,是类图的变化,一个对象图可看成一个类图的示例(example),对象图表示的是类的对象实例而不是真实的类。由于对象存在生命周期,因此对象图只能在系统某一时间段存在。

  对象图中并无新的表示法(除了对象名下要加下划线以外),与类图中的表示法一样,可以认为,只有对象而无类的类图就是一个“对象图”。

UML简明教程
图3.7 对象图

  在对象图中,对象名可以有三种表示形式:

  (1)对象名:类名

  (2):类名

  (3)对象名

  图3.7中的是第1种,即“对象名:类名”格式。

  实质上,对象图几乎很少被用到(它包含的信息量太小,仅仅用于呈现某一时刻对象的值,对软件的设计几乎没有太大的帮助),使用远没有类图广泛。我们可以这样类比类图和对象图之间的关系:

  “动词+名词”构成“动名词”,例如动词“爱”+名词“国”构成动名词“爱国”。

  我们可以看到,“动名词”的信息量很大,很抽象,而作为动名词的例子的“爱国”信息量很小,具体程度很高。

  动名词 ―――――> 类图

  爱国  ―――――> 对象图

  把“动名词”看作类图,把“爱国”看作对象图,很明显,对象图就是类图的一个example而已。

你可能感兴趣的:(UML)