分享

UML建模详解(5)

 WindySky 2018-03-06

1.  类图的组成

        类图(Class Diagram)是由类、接口等模型元素以及它们之间的关系组成的。类图的目的在于描述系统的构成方式,而不是系统是如何协作运行的。

        类:类是面向对象系统组织结构的核心。类是对一组具有相同属性、操作、关系和语义的事物的抽象。这些事物包括了现实世界中的物理实体、商业事务、逻辑事物、应用事物和行为事物等,甚至还包括纯粹的概念性事物。根据系统抽象程度的不同,可以在模型中创建不同的类。

        在UML中,类被表述成为具有相同结构、行为和关系的一组对象的描述符号。所用的属性与操作都被附在类中。类定义了一组具有状态和行为的对象。其中,属性和关联用来描述状态。属性通常使用没有身份的数据值来表示,如数字和字符串。关联则使用有身份的对象之间的关系表示。行为由操作来描述,方法是操作的具体实现。对象的生命周期则由附加给类的状态机来描述。

        在UML的图形表示中,类的表示法是一个矩形,这个矩形由三个部分构成,分别是类的名称(Name)、类的属性(Attribute)和类的操作(Operation)。类的名称位于矩形的顶端,类的属性位于矩形的中间部位,而矩形的底部显示类的操作。中间部位不仅显示类的属性,还可以显示属性的类型以及属性的初始化值等。矩形的底部也可以显示操作的参数表和返回类型等,如图1所示。

                                             

        在类的构成中还应当包含类的职责(Responsibility)、类的约束(Constraint)和类的注释(Note)等信息。

        在Rational Rose 2007中,还可以定制显示的信息,比如需要隐藏的属性或者是操作,以及熟悉或操作的部分信息等。当在一个类图中画一个类元素时,必须要有顶端的区域,下面的两个区域是可选择的,比如当使用类图仅仅显示类元之间关系的高层细节时,下面的两个区域是不必要的,可以隐藏掉类的属性和操作信息,如图2所示。

        类也拥有不同的构造型,在Rational Rose 2007中默认支持ActorBoundaryBusiness ActorBusiness DocumentBusiness EntityBusiness EventBusiness GoalBusiness WorkercontrolDomainentityInterfaceLocationPhysical WorkerResourceServiceTableView等构造型,同样也可以自己创建新的构造型,比如为窗体类创建Form构造型。通过构造型还可以方便地将类进行划分,比如,当需要迅速地查找到模型中所有窗体时,那么之前将所有的窗体都指定成为Form构造型后,只需要寻找Form构造型的类即可。在默认支持的这些构造型中,它们与类的一般图形表示有所不同。如图3所示,是将"User"类的构造型设置成为Table的图形。对于这些构造型的用途,在后面创建具体的类时会进行说明。

                                                                                 

                                                                                    图 2 “Table”构造型的类

        我们也可以为类指定相关的类型,在Rational Rose 2007中默认支持ClassParameterizedClassInstantiatedClassClassUtilityParameterizedClassUtilityInstantiatedClassUtilityMetaClass等类型。不同类型的类的表示图形也不相同。

1. 类的名称

        类的名称(Name)是每个类的图形中所必须拥有的元素,用于同其他类进行区分。类的名称通常来自于系统的问题域,并且尽可能地明确表达要描述的事物,不会造成类的语义冲突。类的名称应该是一个名词,且不应该有前缀或后缀。按照UML的约定,类的名称的首字母应当大写,如果类的名称由两个单词组成,那么将这两个单词合并,第二个单词的首字母也大写。类的名称的书写字体也有规范,正体字说明类是可被实例化的,斜体字说明类为抽象类。如图3所示,代表的是一个名称为"User"的抽象类。

                                                                                   

                                                                                    

        类在它的包含者内有唯一的名字,这个包含者通常是一个包,但也可能是另外一个类。包含者对类的名称也有一定的影响。在类中,默认显示包含该类所在的名称,如图4所示。

       上图中表示一个名称为"NewTeacher"的类位于名称为"NewTeacher"的包中。在一些关于UML的书中,也将其表示成NewTeacher::NewTeacher的形式,将类的名称分为简单名称和路径名称。单独的名称,即不包含冒号的字符串叫做简单名(Simple Name)。用类所在的包的名称作为前缀的类名叫做路径名(Path Name)

2. 类的属性

        类的属性(Attribute)是类的一个特性,也是类的一个组成部分,描述了在软件系统中所代表对象具备的静态部分的公共特征抽象,这些特性是这些对象所共有的。当然,有时候,也可以利用属性值的变化来描述对象的状态。一个类可以具有零个或多个属性。

UML中,类的属性的语法表示为([ ]内的内容是可选的)

[可见性属性名称 [:属性类型]  [=初始值] [{属性字符串}] 

例如,上面所举的"User"类的属性如表1所示。

        表1 "User"类中的属性示例

2.  类(2

(1) 可见性

        属性的可见性描述了该属性是否对于其他类能够可见,从而是否可以被其他类引用。类中属性的可见性包含三种,分别是公有类型(public)、受保护类型(protected)和私有类型(private)。在Rational Rose 2007中,类的属性设置中添加了Implementation选项。如表7-3所示,显示了在Rational Rose 2007中类属性的可见性。

表2类属性的可见性:

Rational Rose 2007中,类的属性可以选择上面四种类型中的任意一种,默认情况下选择私有类型。

(2) 属性的名称

        属性是类的一部分,每个属性都必须有一个名字以区别于类的其他属性。通常情况下,属性名由描述所属类的特性的名词或名词短语构成。按照UML的约定,属性名称的第一个字母小写,如果属性名称包含了多个单词,则这些单词要合并,并且除了第一个英文单词外其余单词的首字母要大写。

(3) 属性类型

        属性也具有类型,用来指出该属性的数据类型。典型的属性类型包括BooleanIntegerByteDateStringLong等,这些被称为简单类型。这些简单类型在不同的编程语言中会有所不同,但基本上都是支持的。在UML中,类的属性可以是任意的类型,包括系统中定义的其他类,都可以被使用。当一个类的属性被完整定义后,它的任何一个对象的状态都由这些属性的特定值决定。

(4) 初始值

        在程序语言设计中,设定初始值通常有如下两个用处。

        用来保护系统的完整性。在编程过程中,为了防止漏掉对类中某个属性的取值,或者类的属性在自动取值的时候破坏系统的完整性,可以通过赋初始值的方法保护系统的完整性。

        为用户提供易用性。设定一些初始值能够有效地帮助用户输入,从而为用户提供很好的易用性。

(5) 属性字符串。

        属性字符串是用来指定关于属性的一些附加信息,比如某个属性应该在某个区域有限制。任何希望添加在属性定义字符串中但又没有合适地方可以加入的规则,都可以放在属性字符串中。

3. 类的操作

类的操作(Operation)指的是类所能执行的操作,也是类的一个重要组成部分,描述了在软件系统中所代表的对象具备的动态部分的公共特征抽象。类的操作可以根据可见性的不同由其他任意对象请求以影响其行为。属性是描述类的对象特性的值,而操作是通过操纵属性的值改变或执行其他动作的。操作有时被称为函数或方法,在类的图形表示中,它们位于类的底部。一个类可以有零个或多个操作,并且每个操作只能应用于该类的对象。

操作由一个返回类型、一个名称以及参数表来描述。其中,返回类型、名称和参数表一起被称为操作签名(Signature of the Operation)。操作签名描述了使用该操作所必需的所有信息。在UML中,类操作的语法表示为([ ]内的内容是可选的)

[可见性操作名称 [(参数表)]  [:返回类型] [{属性字符串}] 

例如,上面所举的"User"类的操作如表2所示。

表3 "User"类的操作:

(1) 可见性

属性的可见性描述了该属性是否对于其他类能够可见,从而是否可以被其他类引用。类中属性的可见性包含三种,分别是公有类型(public)、受保护类型(protected)和私有类型(private)。在Rational Rose 2007中,类的属性设置中添加了Implementation选项,如表4所示:

表4类操作的可见性:



Rational Rose 2007中,类的操作可以选择上面四种类型的任意一种,默认情况下为公有类型,即public类型。

(2) 操作的名称

操作作为类的一部分,每个操作都必须有一个名称以区别于类中的其他操作。通常情况下,操作名由描述所属类的行为的动词或动词短语构成。和属性的命名一样,操作名称的第一个字母小写,如果操作的名称包含了多个单词,则这些单词需要合并,并且除了第一个英文单词外其余单词的首字母要大写。

(3) 参数表

参数表就是由类型、标识符对组成的序列,实际上是操作或方法被调用时接收传递过来的参数值的变量。参数采用"名称:类型"的定义方式,如果存在多个参数,则将各个参数用逗号隔开。如果方法没有参数,则参数表就是空的。参数可以具有默认值,也就是说,如果操作的调用者没有提供某个具有默认值的参数的值,那么该参数将使用指定的默认值。

(4) 返回类型

返回类型指定了由操作返回的数据类型。它可以是任意有效的数据类型,包括我们所创建的类的类型。绝大部分编程语言只支持一个返回值,即返回类型至多一个。如果操作没有返回值,在具体的编程语言中一般要加一个关键字void来表示,也就是其返回类型必须是void

(5) 属性字符串

属性字符串是用来附加一些关于操作的除了预定义元素之外的信息,方便对操作的一些内容进行说明。

4. 类的职责

在标准的UML定义中,有时还应当指明类的另一种信息,那就是类的职责(Responsibility)。类的职责指的是对该类的所有对象所具备的那些相同的属性和操作共同组成的功能或服务的抽象。类的属性和操作是对类的具体结构特征和行为特征的形似化描述,而职责是对类的功能和作用的非形似化描述。有了属性、操作和职责,一个类的重要语义内容就基本定义完毕。

在声明类的职责的时候,可以非正式地在类图的下方增加一栏,将该类的职责逐条描述出来。对类职责的描述并不是必须的,因此也可以将其作为文档的形似存在,也就是说类的职责其实只是一段或多段文本描述。一个类可以有多种职责,设计好的类一般至少有一种职责。

5. 类的约束

      类的约束(Constraint)指定了该类所要满足的一个或多个规则。在UML中,约束是用一个大括号括起来的文本信息。在使用Rational Rose 2007表达类与类之间的关联时,通常会对类使用一些约束条件。如图5所示,指出了在"Student"类和"Read"类之间应当满足的约束。

                                        

                                                                      图5. 约束示例

6. 类的注释

使用注释(Note)可以为类添加更多的描述信息,也是为类提供更多描述方式中的一种,如图6所示:

                                               

                                                                       图6.类的注释

接口:

接口(Interface)是在没有给出对象的实现和状态的情况下对对象行为的描述。通常,在接口中包含一系列操作但是不包含属性,并且它没有外界可见的关联。我们可以通过一个或多个类或构件来实现一个接口,并且在每个类中都可以实现接口中的操作。

接口是一种特殊的类,所有接口都是有构造型<>的类。一个类可以通过实现接口来支持接口所指定的行为。在程序运行的时候,其他对象可以只依赖于此接口,而不需要知道该类关于接口实现的其他任何信息。一个拥有良好接口的类具有清晰的边界,并成为系统中职责均衡分布的一部分。

UML中,接口的表示方式是使用一个带有名称的小圆圈来表示的,并且可以通过一条Realize(实现关系)线与实现它的类相连接,如图7所示:
                                                        

                                                                                    图7 接口示意图

当接口被其他类依赖的时候,也就是说一个接口在某个特定类中实现后,一个类通过一个依赖关系与该接口相连接。这时,依赖类仅仅是依赖于指定接口中的那些操作,而不依赖于接口实现类中的其他部分。在依赖类中可以通过一些方式调用接口中的操作,这种关系如图8所示:

                                              

接口也可以像类那样进行一般化和特殊化处理。在类图中,接口之间的泛化关系也是用类泛化关系所使用的符号表示的,如图9所示:

                                                              

3 类之间的关系(1

       类与类之间的关系最常用的通常有四种,它们分别是依赖关系(Dependency)、泛化关系(Generalization)、关联关系(Association)和实现关系(Realization),如表所示。

表5 关系的种类:



1.
依赖关系(Dependency)

依赖表示的是两个或多个模型元素之间语义上的连接关系。它只将模型元素本身连接起来而不需要用一组实例来表达它的意思。它表示了这样一种情形,提供者的某些变化会要求或指示依赖关系中客户的变化。也就是说依赖关系将行为和实现与影响其他类的类联系起来。

根据这个定义,依赖关系包括有很多种,除了实现关系以外,还可以包含其他几种依赖关系,包括跟踪关系(不同模型中元素之间的一种松散连接)、精化关系(两个不同层次意义之间的一种映射)、使用关系(在模型中需要另一个元素的存在)、绑定关系(为模板参数指定值)。关联和泛化也同样都是依赖关系,但是它们有更特别的语义,故它们有自己的名字和详细的语义。我们通常用依赖这个词来指其他的关系。

依赖关系还经常被用来表示具体实现间的关系,如代码层的实现关系。在概括模型的组织单元,例如包时,依赖关系是很有用的,它在其上显示了系统的构架。例如,编译方面的约束也可通过依赖关系来表示。

依赖关系使用一个从客户指向提供者的虚箭头来表示,并且使用一个构造型的关键字位于虚箭头之上来区分依赖关系的种类,如图10所示:

图中"ClassA"表示的是客户,"ClassB"表示的是提供者,"<<use>>"是构造型关键字,表示使用依赖关系。

                                                

                                                                       图 10 依赖关系                                        

2. 泛化关系(Generalization)

泛化关系用来描述类的一般和具体之间的关系。具体描述建立在对类的一般描述的基础之上,并对其进行了扩展。因此,在具体描述中不仅包含一般描述中所拥有的所有特性、成员和关系,而且还包含了具体描述补充的信息。

在泛化关系中,一般描述的类被称作父类,具体描述的类被称作子类。如,交通工具可以被抽象成是父类,而地铁、巴士、轿车则通常被抽象成子类。泛化关系还可以在类元(类、接口、数据类型、用例、参与者、信号等)、包、状态机和其他元素中使用。在类中,术语超类和子类分别代表父类和子类。

        泛化关系描述的是"is a kind of"(是……的一种)的关系,它使父类能够与更加具体的子类连接在一起,有利于对类的简化描述,可以不用添加多余的属性和操作信息,通过相关继承的机制方便地从其父类继承相关的属性和操作。继承机制利用泛化关系的附加描述构造了完整的类描述。泛化和继承允许不同的类分享属性、操作和它们共有的关系,而不用重复说明。

泛化关系是使用从子类指向父类的一个带有实线的箭头来表示的,指向父类的箭头是一个空三角形,如图11所示:

                                             

       图中,交通工具为父类,巴士,轿车为子类。多个泛化关系可以用箭头线组成的树来表示,每一个分支都指向一个子类。

泛化关系的第一个用途是定义可替代性原则,即当一个变量(如参数或过程变量)被声明承载某个给定类的值时,可使用类(或其他元素)的实例作为值,这被称作可替代性原则(Barbara Liskov提出)。该原则表明无论何时祖先被声明,后代的一个实例都可以被使用。例如,如果交通工具这个类被声明,那么地铁,巴士和轿车的对象就是一个合法的值了。

       泛化使得多态操作成为可能,即操作的实现是由它们所使用的对象的类,而不是由调用者确定的。这是因为一个父类可以有许多子类,每个子类都可实现定义在类整体集中的同一操作的不同变体。例如,地铁和巴士的对象会有所不同,它们中的每一个都是父类交通工具的变形,这一点特别有用,因为在不需要改变现有多态调用的情况下就可以加入新的类。一个多态操作可在父类中声明而无实现,其后代类需补充该操作的实现。由于父类中的这种不完整操作是抽象的,其名称通常用斜体表示,也就是父类是抽象类,如图12所示:

                                               

       泛化的另一个用途是在共享祖先所定义的成分的前提下允许它自身定义其他的成分,这被称作继承。继承是一种机制,通过该机制可以将对类的对象的描述从类及其祖先的声明部分聚集起来。继承允许描述的共享部分只被声明一次但可以被许多类共享,而不是在每个类中重复声明并使用它,这种共享机制减小了模型的规模。更重要的是,它减少了为了模型的更新而必须做的改变和意外的前后定义不一致。对于其他成分,如状态、信号和用例,继承通过相似的方法起作用。

3. 关联关系(Association)

关联关系是一种结构关系,指出了一个事物的对象与另一个事物的对象之间在语义上的连接。关联描述了系统中对象或实例之间的离散连接,它将一个含有两个或多个有序表的类,在允许复制的情况下连接起来。一个类的关联的任何一个连接点都叫做关联端,与类有关的许多信息都附在它的端点上。关联端有名称、角色、可见性以及多重性等特性。

关联的一个实例被称为链。链即所涉及对象的一个有序表,每个对象都必须是关联中对应类的实例或此类后代的实例。系统中的链组成了系统的部分状态。链并不独立于对象而存在,它们从与之相关的对象中得到自己的身份(在数据库术语中,对象列表是链的键)

最普通的关联是一对类之间的二元关联。二元关联使用一条连接两个类的连线表示。如图13所示,连线上有相互关联的角色名,而多重性则加在各个端点上。

                                           

如果一个关联既是类又是关联,那么它是一个关联类,如图14所示,"NewClass3"便是一个关联类。
                                                 

 类之间的关系(2

关联关系还有两种非常重要的形式,分别是聚集(Aggregation)关系和组成(Composition)关系。

聚集(Aggregation)关系描述的是部分与整体关系的关联,简单地说,它将一组元素通过关联组成一个更大、更复杂的单元,这种关联关系就是聚集。聚集关系描述了"has a"的关系。在UML中,它用端点带有空菱形的线段来表示,空菱形与聚集类相连接,其中头部指向整体。如图15所示,表示"NewClass""NewClass2"的聚集关系,其中在"NewClass"中包含"NewClass2"

        组成(Composition)关系则是一种更强形式的关联,在整体中拥有管理部分的特有职责,有时也被称为强聚合关系。在组合中,成员对象的生命周期取决于聚合的生命周期,聚合不仅控制着成员对象的行为,而且控制着成员对象的创建和结束。在UML中,组合关系使用带实心菱形头的实线来表示,其中头部指向整体。如图16所示。心脏与肺、人之间形成组成关系,其中,""类中包含"心脏"类和""类,"心脏"类和""类不能脱离""类而独立存在。

                                     

                                        

       多重性是指在关联关系中,一个类的多个实例与另外一个类的一个实例相关。关联端可以包含有名字、角色名和可见性等特性,但是最重要的特性是多重性,多重性对于二元关联很重要,因为定义n元关联很复杂。多重性可以用一个取值范围、特定值、无限定的范围或一组离散值来表达。

UML中,多重性是使用一个以".."分开的两个数值区间来表示的,其格式为"minimum..maximum",其中minimummaximum都是整数。当一个端点给出多个赋值时,就表示该端点可以有多个对象与另一个端点的一个对象进行关联。如表6所示,列出了一些多重值及解释它们含义的例子。

表6 关联的多重性示例:

    

    

0

仅为0

0..1

0个或1

0..n

0个到无穷多个

1

恰为1

1..n

1个到无穷多个

n

无穷多个

3

3

0..5

0个到5

5..15

5个到15

4. 实现关系(Realization)

       实现关系将一种模型元素(如类)与另一种模型元素(如接口)连接起来,说明和其实现之间的关系。在实现关系中,接口只是行为的说明而不是结构或者实现,而类中则要包含其具体的实现内容,可以通过一个或多个类实现一个接口,但是每个类必须分别实现接口中的操作。虽然实现关系意味着要有像接口这样的说明元素,但它也可以用一个具体的实现元素来暗示它的说明(而不是它的实现)必须被支持。例如,这可以用来表示类的一个优化形式和一个简单形式之间的关系。

       泛化和实现关系都可以将一般描述与具体描述联系起来。泛化将在同一语义层上的元素连接起来(如在同一抽象层),并且通常在同一模型内。实现关系将在不同语义层内的元素连接起来(如一个分析类和一个设计类,一个接口与一个类),并且通常建立在不同的模型内。在不同发展阶段可能有两个或更多的类等级,这些类等级的元素通过实现关系联系起来。两个等级无需具有相同的形式,因为实现的类可能具有实现依赖关系,而这种依赖关系与具体类是不相关的。

       在UML中,实现关系的表示形式和泛化关系的表示符号很相似,使用一条带封闭空箭头的虚线来表示,如图17所示,接口类为"ClassA",具体的实现类为"ClassB"

                                                 

       在UML中,接口是使用一个圆圈来进行表示的,并通过一条实线附在表示类的矩形上来表示实现关系,如图18所示,表示"ClassA"类实现"InterfaceA""InterfaceB"接口。

                                                                    


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多