类图是UML模型中静态视图。它用来描述系统中的有意义的概念,包括具体的概念、抽象的概念、实现方面的概念等。如在图书馆借阅系统中,图书、借书、还书、读者、超期罚款等,这些都是这个系统中的一些有意义的概念。
在前面的文章中曾经说过,静态视图包括类图和对象图。
这篇文章重点介绍类图。
类图(Class Diagram)是描述类、接口、协同以及他们之间关系的图,用来显示系统中这些概念的静态结构。
类图是其它图的基础。我们可以在类图的基础上,使用状态图、协作图、组件图和配置图等。
类图的主要作用有:
(1)对系统的词汇进行建模
(2)对简单的协作进行建模
(3)对逻辑数据库模式进行建模
类图主要由类、接口和各种关系组成。
关系主要包括泛化关系、依赖关系、关联关系和实现关系。
下面将对这些内容进行详细的讲解。
在UML中,一个类通常由名称(Name)、属性(Attribute)和操作(Operation)构成。除此之外,类的构成还包含类的职责(Responsibility)、约束(Constraint)和注释(Note)等信息。
在UML中,类使用下面的图形来表示。
类的图形符号从上到下分为三部分:类的名称、类的属性和类的操作。
在实际中可能还有如下三种形式:
类的名称应该是一个名词,类名应该准确清晰的反映出问题域中的概念。按照UML的约定,类的名称中的每个词的首字母应大写,且使用正体名称来表示可实例化的类,使用斜体名称表示抽象的类。
上面图的Book类就是一个可实例化的类,而下面的这个Shape类属于抽象类。
抽象类的名称使用斜体。
类的名称可以加上路径名称。如下图所示的例子:
上图说明Order这个类来自Business包中。
也可以在命名时写成如下的形式:
Business::Order
::左边是包的名称,右边是类的名称。
类的属性(Attribute)用于描述类的一个特征,这个特征是类的每个实例所共有的。一个类可以有零到多个属性。
在UML中,类的属性定义语法如下:
[可见性] 属性名称 [:数据类型] [=初始值] [{属性字符串}]
上面的语法中,[]中的内容表示是可选的。
(1)可见性
可见性用于控制该属性被类的外部成员的可访问性。主要有以下四种情况:
+:公有属性,其它类可以访问该属性
-:私有属性,不能被其它类访问(默认为私有)
#:保护属性,只能被本类及其派生类访问
~:包内可见,可以被本包中的其它类访问
(2)属性名称
能够准确描述类特征的一个标识符,属性名通常是一个名词或名词短语。一般单字属性使用小写字母,多字属性从第2个单词开始,每个单词的第一个字符要大写。
(3)数据类型
属性所属的数据类型,如布尔类型、整型、浮点型,也可以是用户自定义的类型。
(4)初始值
属性的默认值,在类的实例没有赋其它值时,将采用该值作为该属性的值。
(5)属性字符串
用来指定该属性的其它信息。任何希望进一步描述该属性又没有合适的地方时都可以放在此处。
以上关于属性的描述内容虽然很多,但一般属性的可见性和属性名称是必需的部分。
类的操作是类的行为特征或动态特征。类的操作相当于该类提供的一项服务,该服务可以由类的任何对象请求以影响其行为。操作在面向对象编程中通常被称为函数或方法。
一个类可以拥有多个操作,也可以没有操作。
在UML中,类的操作描述语法如下:
[可见性] 操作名称 [(参数表)][:返回类型][{属性字符串}]
(1)可见性
与属性相同,规定该操作的可访问范围。
操作的可见性也是有+(公有)、-(私有),#(保护)和~(包内可见)四种。
从上到下分别为公有,保护和私有操作
(2)操作名称
在实际建模中,操作名是用来描述所属类的行为的动词或动词短语。在UML中,和属性名的表示类似,单字的操作名小写;多字的操作名,除第一个单词外,其余单词的开头字母要大写。
(3)参数表
是一些按顺序排列的属性定义了操作的输入。
参数表是可选的。
参数的定义使用“名称:类型”的定义方式。
如果存在多个参数,则将各个参数用逗号隔开。
参数可以具有默认值,适用调用时没有提供参数值的情况。
如下面的time,其类型为Date,默认值为currentdate(即当前时间)
(4)返回类型
此项为可选项目,即操作不一定必须有返回类型。但在具体编程语言中使用void关键字来代表这种无返回值的情况。
(5)属性字符串
任何在其它地方没有描述清楚的内容都可以在这里进行描述。
在UML中,可以在操作部分的下面再添加一个区域,用来说明类的职责。即说明类或其它元素的契约或义务。
创建一个类时,同时声明这个类的所有对象具有相同种类的状态和相同种类的行为,在较高层次上,这些相应的属性和操作正是要完成类的职责和特性。
职责可以使用一个短语、一个句子或一段短文的形式来描述。
在draw.io中,可以在“通用”组图形中添加一个矩形,然后把矩形拖拽到类图标上,当类周围边框变了颜色后,松开鼠标,就可以在类图标的底部添加一个分隔的矩形,然后可以输入类的职责相关描述。如下图所示:
类的约束指定了该类所要满足的一个或多个规则。
在UML中,约束使用一个大括号括起来的文本信息。
如上图中类符号下面花括号中的内容,即是对该类的约束。
接口是在没有给出对象的实现和状态的情况下对对象行为的描述。
接口包含操作但不包含属性,且它没有对外界可见的关联。
一个类可以实现一个或多个接口,从而支持接口所指定的操作。
接口可以使用下面两种形式来表示:
使用<<interface>>构造型
使用一个圆圈
在类图中的关系有四种:
依赖关系(dependency):表示类之间使用关系
泛化关系(generalization):表示一般和特殊关系
关联关系(association):表示对象之间结构关系
实现关系(realization):表示规格说明和实现之间关系
它表示这样一种情形,对于一个元素(提供者)的某些改变可能会影响或提供消息给其它元素(客户),即客户以某种形式依赖于其它类元。
主要的情形为:
客户类的操作需要提供者类的参数;
客户类的操作返回提供者类;
客户类的操作在实现中使用提供类的对象。
下面举个例子来说明这三种情形:
使用Java程序来表示上面这种情形:
上面这段代码表示了常见类之间依赖关系的三种情形:提供者类作为参数、提供者类作为方法的返回类型、提供者类作为方法中的一个变量。
该关系是存在于一般元素和特殊元素之间的分类关系。其中,特殊元素与一般元素兼容,且还包含自己特有的信息。
泛化可以用于类、接口、用例、参与者、包、状态机以及其它模型元素。
泛化关系描述的是“is a kind of”的关系。
泛化关系使用带空心三角形的箭头来表示,箭头从子类指向父类。
下面是一个车辆Vehicle与Truck之间的泛化表示。
实现这种关系的Java代码如下:
关联关系是一种结构关系,指出了一个事物的对象与另一个事物的对象之间的语义上的连接。
关联的任何一个连接点都叫做关联端。关联端可以有自己的角色、多重性、可见性等修饰。关联也可以有自己的名称。
在UML中,关联关系用一条连接两个类的实线表示。
上面的图中,“拥有”为关联的名称,“客户”为类Person的角色,“交通工具”为类car的角色。角色也可以有自己的可见性,“客户”和“交通工具”前的“+”即代表其可见性为公有。
关联端的“1”和“0..n”是描述的多重性,下面将会做进一步的介绍。
关联的多重性(Multiplicity)是指有多少个对象可以参与该关联。
其可用来表达一个取值范围、特定值、无限定的范围或一组离散值。
多重性是UML中使用最广泛的约束。
主要有以下几种形式:
形式 | 含义 | 形式 | 含义 |
0 | 恰为0 | 0..n | 0到多个 |
1 | 恰为1 | 1..n | 1到多个 |
0..1 | 0或1 | 3..n | 3到多个,至少3个 |
n | 0或多个 | 3,5,7 | 3个,或5个,或7个 |
关联关系又可以分为单向关联、双向关联、自关联、聚合关联和组合关联四种情形。
(1)单向关联
单向关联用带箭头的实线表示。箭头由源类指向目标类。
这种关联实际上是带导航的关联。它指在源类中要使用目标类的对象作为成员。
上面类之间的关系可以使用下面的Java代码来表示:
(2)双向关联
双向关联关系不再绘制箭头,使用直线直接连接两个类即可,如下面两个类之间的关系即是双向关联关系:
实现这种关系的Java代码可以如下表示:
带有角色修饰的双向关联:
实现这种关联关系的Java代码可表示如下:
(3)自关联
自关联关系即一个类与自己进行关联。
上面类关系的意思是employee类中有一个为employee类型的leader成员,表示员工的领导。
使用Java代码可以表示如下形式:
public class employee{ private employee leader;}
(4)聚合关联
它表示整体与部分关系的关联。
关联关系中一组元素组成了一个更大、更复杂的单元
聚合关系描述了“has a ”的关系。
在UML中聚合关系用带空心菱形头的实线来表示,头部指向整体。
这种关系中的空心菱形并不是箭头,它只表明哪端是整体。
聚合的双向关联的一个例子:
它表示College类是University类的一个聚合成分。
使用Java实现的代码如下所示:
如果是单向的可以使用下面的方式来表示:
跟上面那个例子的区别是,这种聚合关联只在University类中声明College类的成员对象,不在College类中声明University的成员对象。
使用Java代码实现如下:
当然单向的聚合关系也可以表示下图的形式:
使用Java代码实现如下:
这样的聚合表示没太大意义。
(5)组合关联
是聚合的一种特殊情况,是更强形式的聚合(即强聚合)。
成员的生命周期取决于聚合的生命周期。
聚合不仅控制着成员对象的行为,而且控制着成员对象的创建和解构。
在UML中,组合使用带实心菱形头的实线来表示,其菱形在整体这一端。
上面的Triangle类由多个Side类对象组合而成,当Triangle对象创建时,Side的对象被创建,Triangle对象被销毁时,其Side对象也将被销毁。
使用Java代码实现如下:
是关于规格说明和其实现之间的关系,它将一种模型元素与另一种模型元素连接起来,比如类和接口。
实现关系将不同语义层上的元素连接起来。
实现关系不仅使用于接口和类之间,也可以是类的不同等级之间的联系,如粗设计与细设计之间。
实现一般使用带空心三角形的虚线箭头表示,箭头指向接口。
下面是关于接口和实现接口类之间的标识方法。
下面是一个具体的接口和实现之间的例子。
IUser是一个接口,VipUser是一个类,VipUser类要实现接口IUser。
其Java代码可以表示成下面的形式:
建立类图的过程就是对领域问题及其解决方案的一个分析和设计的过程。
关键是要准确地找出现实世界的对象类和类之间的联系。
建立类图的一般步骤:
研究分析问题领域,确定系统的需求。
发现对象与对象类,明确他们的含义和责任,确定属性和操作。
发现类之间的静态联系;
设计类与联系;
绘制类图并编制相应的说明。
下面继续以前面文章中(UML系列内容之五:一个用例图案例)介绍的案例来设计其类图。
案例中可以分析出以下几个类:
经过认真分析类之间的关系,使用Rose工具绘制的类图如下:
以上内容仅供参考,如有问题,请留言说明。
新闻热点
疑难解答