《C++面向对象高效编程(第2版)》——2.24 Booch 中类的关系

简介:

本节书摘来自异步社区出版社《C++面向对象高效编程(第2版)》一书中的第2章,第2.24节,作者: 【美】Kayshav Dattatri,更多章节内容可以访问云栖社区“异步社区”公众号查看。

2.24 Booch 中类的关系

C++面向对象高效编程(第2版)
发现类并建立类之间的关系,是分析和设计过程中最重要的阶段。

Booch方法论在类之间使用两种主要关系—— is-a关系和has-a关系。关系的完整列表如下:

关联(association)
继承(inheritance)(is-a)
聚集(aggregation)(has-a)
使用(using)
实例(instantiation)(模板)
元类(metaclass)

image

图2-6

2.24.1 关 联

关联(association)用于分析的早期阶段,最终会成为has-a、is-a或者“使用”关系。关联是一个双向关系,A的客户可以达到B,而B的客户也可以达到A(见图2-7)。

关系两端的数字代表基数(cardinality),每家银行可以有0..N个客户,而客户可以在0..N家银行中有账号(见图2-8)。

2.24.2 聚 集( has-a )

在这种关系中,A类的实例包含B类的实例(A “has-a”B)。这并不意味着一定是物理上的包含(physical containment)(通过值),也可以通过指针或引用包含。这种关系通常称为“has-a”关系,也称为聚集(aggregation),用于表示整体/部分关系(见图2-9)。

如图2-9所示,关系线上的标注表明了聚集的性质,线两端的数字表示基数。

人可以有多个驾驶执照(不同国家、不同类型的驾驶执照等),也可能一个驾驶执照都没有,这种情况用基数(0..N)表示。换而言之,人可以有0个或者多个驾驶执照。符号●说明“has-a”关系的源头。该例中,一个Person有一个(或多个)DrivingLicense。在给定Person对象的情况下,可以查找(或枚举(enumerate)) Person所拥有的DrivingLicense。但是,在给定DrivingLicense对象的情况下,不可能找到它所属的Person。这是因为“has-a”是单向关系,符号●表示关系的源头。Person类对象旁的数字1表明任何DrivingLicense对象都只属于一个Person。关系的名称“持有”也标在图2-9中。
image

图2-8

“has-a”关系可以通过指针、引用或者甚至通过包含的对象来实现(见表2-2)。也就是说,“has-a”并不意味着每个Person类对象在物理上都包含许多DrivingLicense类对象(尽管也可能这样实现)。

表2-2 has-a关系中基数的选择

image

“has-a”关系和“is-a”关系可以说是类之间最常用的关系。本书很多地方都使用has-a关系来表示类之间某些类型的包含关系。注意,“has-a”是一个通用术语,它的含义很多。例如,多人共同拥有度假屋,就可以表示为Person和VacationHome之间的“has-a”关系。

image

图2-10

类似地,公司雇佣职员也是这样,仍然可以表示为Employee和Company之间的has-a关系(见图2-10)。关系的名称可以帮助我们更易理解关系的性质。

在职员—公司关系中,“为其工作”是从雇员的角度说明两者的关系。如果给定Employee类对象,我们可以找到她所工作的Company(一个或多个);如果给定Company类对象,为了找到Employee,还需要另一种关系,如上图的“聘用/雇佣”关系所示。这允许我们为给定的Company类对象找到Employee,这种双向关系很常见。按照这样的分析思路,请注意,不可能在任何时候都为特定的VacationHome找到所有与之关联的Person,因为在VacationHome到Person之间不存在任何关系。从Person到VacationHome之间存在“has-a”关系,而从VacationHome到Person之间没有这种关系。这就是“has-a”语句是单向关系的含义。在“共同拥有”关系中,Person旁有一个基数(0..N)。这只表明VacationHome可以同时被Person(一人或多人)拥有。很明显,Person类对象在物理上并未包含VacationHome类对象在内。

再来看另一个“has-a”关系的例子。汽车有一个引擎,也就是说,Car在物理上包含一个Engine,这种情况可以用线末尾的实心方块■表示,如图2-11所示。另外,空心方块□代表通过引用包含。

该例中,每个Car类对象都有自己的Engine类对象,这是真实的物理包含关系。而且,每个Car都有1个Engine类对象,如基数所示。每个Engine有4个或更多的Cylinder(汽缸),如图2-11所示。

“has-a”关系表示一种生存期—控制的关系。被包含的Engine类对象的生存期,由包含它的Car类对象所控制。当创建Car类对象时,也创建了Engine类对象;当销毁Car类对象时,也销毁了Engine类对象(它是Car的一部分)。

2.24.3 “使用”关系

“使用”关系用于表示大多数的客户—供应商关系。如果A类将B类作为A类成员函数的参数接收(或者从A类的成员函数返回B类对象),并且和B类没有任何其他类型的关联,此时A类使用B类。如果B类用于A类的某个方法的实现中,也存在“使用”关系。空心圆圈○表示“使用”关系。

在图2-12中,MailGateway(邮件网关)正在使用MessagePacket(消息包)。记住,“使用”关系并不意味着“has-a”关系。如果MailGateway储存MessagePacket类对象(以某种形式),那么MailGateway就有一个MessagePacket,这就没必要用“使用”关系。“has-a”关系是“使用”关系的超集,而且“has-a”比“使用”关系的功能更强大。

在问题的解决方案中,“使用”关系并不常见。
image

2.24.4 继承关系(is-a)
“is-a”关系用于表示继承,意味着从基类到派生类的一般-特殊关系(见图2-13)。

Manage(经理)是一个Employee(雇员)。箭头从派生类(Manage)指向基类(Employee)。在后面的章节中,将详细介绍继承。

大多数问题的解决方案都使用“has-a”和“is-a”关系的组合。“has-a”和“is-a”都是非常强大的关系,它们各有优缺点。设计者必须清楚地理解何时使用“is-a”关系,何时使用“has-a”关系。本书中有许多示例都阐述了两者之间的差别。

2.24.5 类范畴

大多数项目都不可能在一张纸上显示出该项目涉及的所有类。为帮助分组(和建模)类,我们使用了类范畴(class category)。类范畴通过包含在其中的类提供服务。类范畴有自己唯一的名称(类似于类)。
image

图2-14

要对整个系统进行高级描述,只能用类范畴(见图2-14)。类范畴的分解图必须显示其中包含的所有类,以及这些类之间的关系。

相关文章
|
1月前
|
算法 Java 程序员
【C++专栏】C++入门 | 类和对象 | 面向过程与面向对象的初步认识
【C++专栏】C++入门 | 类和对象 | 面向过程与面向对象的初步认识
23 0
|
20天前
|
C++
C++从入门到精通:2.1.2函数和类——深入学习面向对象的编程基础
C++从入门到精通:2.1.2函数和类——深入学习面向对象的编程基础
|
26天前
|
C++
面向对象的C++题目以及解法2
面向对象的C++题目以及解法2
31 1
|
26天前
|
C++
面向对象的C++题目以及解法
面向对象的C++题目以及解法
19 0
|
28天前
|
编译器 C语言 C++
【C++成长记】C++入门 | 类和对象(上) |面向过程和面向对象初步认识、类的引入、类的定义、类的访问限定符及封装
【C++成长记】C++入门 | 类和对象(上) |面向过程和面向对象初步认识、类的引入、类的定义、类的访问限定符及封装
|
6天前
|
设计模式 安全 算法
【C++入门到精通】特殊类的设计 | 单例模式 [ C++入门 ]
【C++入门到精通】特殊类的设计 | 单例模式 [ C++入门 ]
16 0
|
7天前
|
C语言 C++
【C++】string类(常用接口)
【C++】string类(常用接口)
20 1
|
5天前
|
编译器 C++
【C++】继续学习 string类 吧
首先不得不说的是由于历史原因,string的接口多达130多个,简直冗杂… 所以学习过程中,我们只需要选取常用的,好用的来进行使用即可(有种垃圾堆里翻美食的感觉)
7 1