B.2 类 图

B.2.1 类图的概念

类图是静态视图的图形表达方式,表示声明的静态模型元素,如类、类型和其内容,以及它们的相互关系。也就是说,类图是用来描述类以及类与类之间关系的一种UML图。

B.2.2 类图的基本表达

类图的基本模型元素如图B.1所示。

图片

图B.1 类图的基本图示

也就是说,一个类的图形表示为长方形,长方形又分成三个部分,分别是类名、属性定义和操作也就是方法定义。

1.类名的定义

没有特殊要求,任何合法的名称都可以。类名通常为一个名词。为类命名时最好能够反映类所代表的问题的域中的概念,另外类的名字含义要准确、清楚。

2.属性定义的基本语法

属性用来描述类所具有的特征。描述属性的语法格式为:

可见性属性名:类型名=初值

其中属性名和类型名是一定要有的,其他部分可选。

对于可见性:+表示public,—表示private,#表示protected,没有符号就表示是默认的可见性。基本的示例如图B.2所示。

图片

图B.2 带属性的类图

注意

注意一点:Attribute和Property虽然都是表示类的属性,但是一些属性只是在类内部使用,不对外的,一般称这些属性为Attribute;也有一些属性虽然是private的,但是会提供相应的getter/setter方法让外部来操作,把这些属性称为Property。

具体的还是看个示例,给上面的类图添加一个名称为绰号,也就是“nickname”的Property,如图B.3所示。

图片

图B.3 同时有Attribute和Property的类图

3.操作定义的基本语法

操作用来描述类能干些什么事情,也就是我们通常说的方法。描述操作的语法格式为:

可见性操作名(参数列表):返回值类型

可见性和属性的描述方式一样,都是+表示public,-表示private,#表示protected,没有符号就表示是默认的可见性。参数列表由多个参数构成,用逗号分隔,描述参数的语法格式为:

参数名:参数类型名

在图B.3所示的类图中添加一个方法:人能够按照指定的速度和持续时间进行跑步运动,如图B.4所示。

图片

图B.4 带操作的类图

4.Java中static的表示

在类图中,如果属性或者方法是static的,那么在属性或者方法定义的下面,添加一条下划线表示是static的,如图B.5所示。

图片

图B.5 带static的类图

B.2.3 抽象类和接口

抽象类的表示是类名倾斜,抽象操作的表示是整条操作定义都倾斜,如图B.6所示。

图片

图B.6 抽象类的类图

接口是一种特殊的抽象类,归根结底还是类,所以接口的表达基本语法和类是一样的,比如一个有创建用户和删除用户的接口,定义示例如图B.7所示。

图片

图B.7 接口的类图

在其他UML图中,接口还可以用一个圆圈来表示,比如在组件图中。由于本书不涉及到这些知识,这里就不去示例了。

B.2.4 关 系

前面讲到,类图除了描述类本身之外,另外一个重点就是描述类与类之间的关系。在UML2.0中,类图描述的关系包括关联、泛化(也叫通用化或者继承)、依赖、实现、使用和流几种。大致如表B.2所示。

表B.2 关系的种类

图片

1.关联关系

UML的关联用于描述类和类的连接。类与类之间有多种连接方式,每种连接的含义都是不同的,虽然语义不同,但是外部表象类似,因此统称为关联。

关联关系一般都是双向的,也即关联双方都能和对方通信,但是也有单向的关联。根据不同的含义,把关联分成普通关联、递归关联、限定关联、或关联、有序关联、三元关联和聚合七种。本书涉及到了普通关联、递归关联和聚合几种,下面分别来介绍一下这三种关联,其他的关联关系就不再讲述了。

(1)普通关联

只要类与类之间存在关联关系就可以用普通关联来表示。标准的表示是一条直线,但是本书采用的是更严格的表达,如016070001,带叉的这一端,表示关联的发起方,在另一端还可以通过一个箭头来表示被关联的一方,从而表示关联的方向,如016070002

来看看普通关联的示例:描述人和计算机的关系,如图B.8所示。

图片

图B.8 普通关联示例

图B.8中的数字表示重数,比如上面从人到计算机的关联,描述的是一个人拥有0到多个计算机。而另外一条从计算机到人的关联,没有重数,默认都是1,表示一台计算机属于一个人。重数表示示例如下。

a55126e448bd408fbc796fc0475f741b

图B.8所对应的Java示例代码如下:

8d882834e6d54c829b110c9f397ee170

这也是Java中表达对象之间一对多关系的方式,也就是在一的这边,包含一个多的那边对象的集合,而多的这边,包含一个一的那边的对象。

(2)递归关联

如果一个类与它本身有关联关系,那么这种关联关系被称为递归关联。

递归关联描述的是同类的对象之间的语义关系,带有递归的含义,通常情况下都是一对多的关系,如图B.9所示。

图片

图B.9 递归关联示例

当然递归关联也可以是一对一,或者多对多的,这里就不再多讲了。

(3)聚合关联

聚合关联是关联的一种特殊情况,如果类与类之间具有“整体与部分”的关系,使用聚合来表达。

根据语义又把聚合关联分成了三种:普通聚合、共享聚合和复合聚合(也叫组成)。

■ 普通聚合:描述类与类之间具有“整体与部分”的关系。比如班级和学生,班级是整体,而学生是组成班级的部分,如图B.10所示。

图片

图B.10 普通聚合的示例一

可以看出普通聚合的表达方式为,在表示关联关系的这端加上一个空心的菱形,空心的菱形紧靠着具有整体含义的这端,另一端可以没有标示,也可以加上箭头来表示一个方向性,如图B.11所示。

图片

图B.11 普通聚合的示例二

■ 共享聚合:如果聚合关系中,处于部分方的对象参与了多个整体方对象的构成,描述成为共享聚合。比如学习兴趣小组和学生,学习兴趣小组是整体,而学生是组成学习兴趣小组的部分,但是一个学生可以参加多个学习兴趣小组,一个学习兴趣小组有多个学生,如图B.12所示。

图片

图B.12 共享聚合的示例

可以看出在普通聚合中,整体与部分是一对多,而共享聚合中是多对多了。和普通聚合一样,可以在部分这边加上箭头,就不再示例了。

■ 复合聚合:如果构成整体类的部分类,完全隶属于整体类,那么这样的聚合称为复合聚合,也叫组成。比如一个图形界面和组成这个图形界面的按钮、文本框、Label等图形组件之间的关系,图形界面是整体,而各个图形组件是组成界面的部分,如图B.13所示。

图片

图B.13 复合聚合的示例

可以看出复合聚合也是一对多的,只是在一的这端,用一个实心的菱形来表示了。通常复合聚合表达的语义有这样的含义:如果整体对象不存在,那么部分对象也就没有存在的前提或意义了,也就是说整体与部分有非常强烈的包含关系。和普通聚合一样,可以在部分这边加上箭头,就不再示例了。

2.泛化关系

泛化又称通用化或继承,用来描述一个通用元素的所有信息能被另外一个具体元素继承的机制。继承某个类的类除了有自己的属性和操作外,还拥有被继承类中的信息。

比如人员和学生,明显人员是父类,学生作为子类,如图B.14所示。

图片

图B.14 泛化关系的示例

3.实现关系

就是描述类实现接口的关系。接口是对行为而非实现的说明,实现类来具体实现接口中的抽象定义。

比如,写一个实现前面定义的用户操作接口,如图B.15所示。

图片

图B.15 实现关系的示例

4.依赖关系

依赖关系是描述:如果某个对象的行为和实现,需要受到另外对象的影响,那么就说这个对象依赖于其他对象。基本上有关联的地方,严格说都有依赖。现在最常用的依赖关系是“使用”,意思是如果A使用了B,那么A就依赖于B。

比如,写一个Client来使用上面定义的接口和实现,那么这个Client就会依赖接口和实现这两个类,如图B.16所示。

图片

图B.16 依赖关系的示例

Client中的代码示例如下:

ecd34bec5911441bb57da8fe9764f248

事实上,依赖关系描述的是两个模型元素之间语义上的连接关系。常见的除了上面的直接调用外,还有,一个类使用另外一个类来作为操作的参数,一个类有以另外一个类作为类型的属性,甚至包括上面讲到的继承和实现等关系,都可以算是依赖。