在本章中,我们学习了两个对象之间可能存在的几种不同关系。
总结
利用较简单对象构建复杂对象的过程称为对象组合(object composition)。对象组合分为两种:组合(composition)与聚合(aggregation)。
组合(composition)
当类成员与类之间存在“整体-部分”关系,且类负责管理该成员的生存期时,即为组合。要满足组合关系,对象与部分(成员)必须同时满足:- 该部分是对象的一部分;
- 该部分在同一时刻只能属于一个对象;
- 该部分的生存期由对象管理;
- 该部分并不知道对象的存在。
组合通常通过普通成员变量实现,或由指针实现但由类负责所有内存的分配与回收。若一个类能够设计为组合,则应优先使用组合。
聚合(aggregation)
当类与成员之间存在“拥有”关系,但类并不管理成员的生存期时,即为聚合。要满足聚合关系,对象与其部分必须同时满足:- 该部分是对象的一部分;
- 该部分可同时属于多个对象;
- 该部分的生存期不受对象管理;
- 该部分并不知道对象的存在。
聚合通常通过指针或引用实现。
关联(association)
一种更为松散的关系,一个类“使用”一个与其无其他关联的对象。要满足关联关系,对象与被关联对象必须同时满足:- 被关联对象与该类无其他关系;
- 被关联对象可同时属于多个对象;
- 被关联对象的生存期不受该类管理;
- 被关联对象可以知道也可以不知道该类的存在。
关联可通过指针、引用,或更间接的方式(如保存索引或键)实现。
依赖(dependency)
在依赖关系中,一个类使用另一个类来完成某项任务。被依赖的类通常并非当前类的成员,而是临时创建、使用并销毁,或由外部以参数形式传入成员函数。容器类(container class)
一个类提供容器,以保存另一类型的多个对象。- 值容器(value container)是一种组合,保存其所容纳对象的副本。
- 引用容器(reference container)是一种聚合,保存位于容器之外的对象的指针或引用。
std::initializer_list
可用于实现构造函数、赋值运算符及其他接受列表初始化形参的函数。std::initializer_list
位于<initializer_list>
头文件中。
属性 / 类型 | 组合 (Composition) | 聚合 (Aggregation) | 关联 (Association) | 依赖 (Dependency) |
---|---|---|---|---|
关系类型 | 整体-部分 | 整体-部分 | 无其他关联 | 无其他关联 |
成员可否同时属于多个类 | 否 | 是 | 是 | 是 |
成员生存期由类管理 | 是 | 否 | 否 | 否 |
方向性 | 单向 | 单向 | 单向或双向 | 单向 |
关系动词 | part-of | has-a | uses-a | depends-on |
测验时间
本章较为简明且抽象,故测验短小精悍。
请指出下列描述属于哪种关系(组合、聚合、关联或依赖):
1a) 一个 Animal 类包含一个动物类型(枚举)和名字(字符串)。
组合(composition):类型和名字是 Animal 对象不可分割的部分,且生存期由 Animal 管理。
1b) 一个文本编辑器类具有 save() 函数,该函数接收 File 对象作为实参,并将编辑器内容写入磁盘。
依赖(dependency):File 对象并非文本编辑器的成员,仅在 save() 函数执行期间被使用。
1c) 一个 Adventurer 类可携带多种 Items,如剑、法杖、药水或法术书。这些 Items 可以被丢弃并由其他 Adventurer 拾取。
聚合(aggregation):Items 可同时属于多名 Adventurer,且其生存期不由任何一名 Adventurer 管理。
1d) Player 在 Shrine 前祈祷(以获得新能力)。
关联(association):Shrine 与 Player 无整体-部分关系,Player 只是临时“使用” Shrine。
1e) Computer 类包含一个 CPU 类。该 CPU 可从 Computer 中移除并单独测试。
聚合(aggregation):CPU 是 Computer 的一部分,但可独立存在,且生存期不受 Computer 管理。
1f) 一名铁匠拥有一把特定的铁砧,他用它来完成工作。
关联(association):铁砧与铁匠无整体-部分关系,铁匠只是“使用”铁砧。