
3.1 类之间的关系
在应用程序设计过程中通常会遇到多个相互关联的类同时存在的现象。例如,在一个图书管理程序中会出现图书类和读者类,而读者类又可分为教师类和学生类。显然,教师和学生与读者之间是继承关系,而图书与读者之间是一种平等的关联关系。类之间通常会存在有依赖、关联、聚合、组合和继承关系(继承关系将在后续章节中介绍),理解类之间的关系是进行类设计的一个重要环节。
3.1.1 UML简介
在开始讨论类之间关系前,首先需要了解一下用于描述类结构及类之间关系的分析工具UML(Unified Modeling Language,统一建模语言)。UML是一种支持模型化和软件系统开发的图形化语言,它为软件开发的所有阶段提供模型化和可视化的支持。UML表现的是系统的架构,而不能表示代码的细节。
UML的目标之一就是为开发团队提供标准和通用的设计语言,并通过这种语言形成应用的蓝本。通过UML开发人员能够实现对任意系统架构的阅读、理解和交流,它是系统架构设计及实现的一种图形化的利器。
常用的UML图包括用例图、类图、对象图、序列图、状态图、活动图、组件图和部署图。本教材中仅简单介绍使用类图和对象图来表示Java项目的类结构和各元素间的对应关系的方法,其他内容读者可查阅相关资料。
1.类图
类图表示不同的实体间的相互关系,显示了系统的静态结构。类图可用于表示实体的抽象描述。如图3-1所示,类图通常用一个矩形来表示,并在矩形中从上自下分为类名、字段和方法3个部分。

图3-1 UML类图
图中类成员名称前面的符号表示访问修饰符,常用的+、-和#分别表示public、private和protected修饰符,没有使用符号修饰的成员表示使用缺省修饰符。冒号后面表示字段成员数据类型或方法成员的返回值类型。例如,下列代码表示的Circle类可以使用图3-2所示的UML类图表示。

图3-2 Circle类图

2.对象图
使用UML图表示对象时,图3-3所示矩形中从上向下分为对象名和字段值两个部分,上部表示对象名称及所属的类,下部表示对象的各自段及赋值情况。例如,图3-4所示的是下列代码创建的Circle类对象c1和c2的UML对象图。

图3-3 UML对象图

图3-4 Circle类对象c1、c2的UML对象图

3.1.2 依赖关系
依赖关系是指一个类A使用到了另一个类B,而这种使用是具有偶然性、临时性的弱关系。也就是说某个对象的功能实现需要依赖另一个对象,但是被依赖的对象并未被融合到该对象中,它仅仅是当作工具被使用。例如,在图书管理系统中学生类的借阅(borrow)方法是否能执行成功,需要依赖于图书类的库存量(stock)和借出(loan)方法,但学生类并未将图书库存量和借出方法这两个图书类的成员包含进来,执行借阅时它仅仅是当作辅助数据和工具被使用的。如图3-5所示,在UML类图中使用一条从类A指向类B的带箭头的虚线表示这种依赖关系。

图3-5 UML类图表示的依赖关系
3.1.3 关联关系
关联是一种常见的二元关系,它描述了多个类之间的活动,是一种更强的依赖关系。例如,学生选取课程是学生类(Student)和课程类(Course)之间的一种关联。而教师授课是教师类(Teacher)与课程类之间的一种关联。需要注意的是,关联关系中常会出现一对多或多对多的关系。例如,在选课过程中多名学生可以选同一课程,而一门课程只能由一名教师授课。在UML图中关联关系用带箭头的实线表示,在关联的两端可以标注关联双方的角色和多重性标记。
图3-6所示的关联关系表示学生可以选取多门课程,而每门课程可以有5~60名学生;每位教师可以教授0~3门课程,而每门课程只能由一名教师教授。图中黑色三角表示的是关系的方向,它标记了关系中的主动方。例如,是学生选课,而不是课程选学生。

图3-6 UML图表示的关联关系
下列所示的代码表现了学生、课程和教师之间的通过字段和方法实现的关联。

其中Course[]和Student[]表示的是Course类和Student类数组,数组中每个元素均为一个Course类或Student类对象,表示一个具体的课程或一名具体的学生。
3.1.4 聚合与组合
类之间的聚合关系也称为聚集,它是关联关系的一种特例,用来表示整体和部分之间的关系。例如,汽车、发动机和轮胎三者之间的关系。显然,发动机和轮胎是汽车的这个整体的一部分,但是发动机和轮胎可以属于多个不同的汽车整体,而且发动机和轮胎的生命周期也不依赖于汽车的生命周期。也就是说,当一辆汽车销毁时发动机和轮胎还可以继续存在于其他汽车整体中。
在类中,聚合关系与关联关系相同也是通过字段成员来实现的,但它与关联关系的不同点在于关联中涉及的多个类处于相同的级别,而聚合关系中的多个类分为整体和部分两个不同的层次。如图3-7所示,聚合关系在UML类图中以一个空心菱形箭头加实线箭头来表示,空心菱形箭头指向整体类。
组合也是关联关系的一种特例,它体现的仍然是整体与部分之间的关系,但组合中的部分依赖于整体而存在,是不可分割的。也就是说部分的生命周期与整体的生命周期相同,当整体消亡时部分自然也就不存在了。显然,这种关系比聚合更强,所以组合也称为强聚合。例如,人类和头、手、脚等器官的关系就是一种典型的组合关系,器官只能唯一的隶属于某个具体人类不可分割,而且它们具有相同的生命周期。如图3-8所示,在UML图中使用实心的菱形箭头表示组合关系,菱形箭头指向整体部分。

图3-7 UML图表示的聚合关系

图3-8 UML图表示的组合关系