导言
前面文章,我们讲诉了关联关系的,一元关联,二元关联,三元关联以及关联类的知识。今天我们就论述两个关系,一个是聚合关系,一个是组合关系。组合和聚合关系都是关联关系的特例。
前言
组合和聚合都是讨论一个类由其他类构成的情况。
组合和聚合都是关系的特殊形式:类通过整体/部分关系连接起来的。
这两种情况下,部分和整体间的关系是一个Is part of(是….的一部分)关系。
聚合关系(Aggregation)
聚合关系表示一个整体与部分的关系。
聚合关系中,成员类是整体类的一部分,即成员对象是整体对象的一部分,但是成员对象能脱离整体独立对象存在。
在一个聚合里,部分实例能添加到聚合整体中,也能从聚合整体中移除。
聚合被用来概念类建模,而不是物理类建模。
一个部分可以属于多个聚合。
UML中,聚合关系用带空心菱形的直线表示。
聚合关系最大的特点便是其成员对象实例化,并不是在类的构造函数中,而是通过设置注入或者构造注入方式实例化。
例子
汽车发动机(Engine)作为汽车(Car)的组成部分,但汽车发动机可以独立存在。
代码(主要部分)
car类
public class Car {
....
private Engine engine;
public Car(Engine engine) {
this.engine = engine;//构造注入方式,并不在构造函数中实例化
}
public void setEngine(Engine engine) {
this.engine = engine;//设置注入方式
}
...
}
组合关系(Composition)
同聚合关系一样,也表示整体与部分的关系。但组合关系中部分和整体具有统一的生存期。
组合关系中,成员类是整体类的一部分,而且整体类可以控制成员类的生命周期,即成员类的存在依赖于整体类。
组合(整体)类经常涉及到整体与部分之间的物理关系
一旦整体不存在,部分对象也将不存在部分对象和整体对象之间具有同生共死的关系。
在UML中,组合关系用带实心菱形的直线表示。
组合关系的最大特点是在整体类的构造函数需要将部分类进行实例化,使得整体和部分的生存期一致,即成员类依赖于整体类而产生
例子
人的头(Head)与嘴巴(Mouth),嘴巴是头的组成部分之一
如果头没了,嘴巴也就没了。
代码
Head类
public class Head {
...
private Mouth mouth;
public Head() {
this.mouth = new Mouth();//此部分体现了同生共死的关系
}
...
}
关联关系、聚合关系、组合关系区别
聚合和组合的区别在于:聚合关系是“has-a”关系,组合关系是“contains-a”关系;
聚合关系表示整体与部分的关系比较弱,而组合比较强;
聚合关系中代表部分事物的对象与代表聚合事物的对象的生存期无关,一旦删除了聚合对象不一定就删除了代表部分事物的对象。组合中一旦删除了组合对象,同时也就删除了代表部分事物的对象。
代码实现上,聚合关系通过对象注入的方式实现,组合关系通过整体类的构造函数实例化成员类实现,但两者共同点是一个类的实例是另一个类的成员对象。
我们用浅显的例子来说明聚合和组合的区别。“国破家亡”,国灭了,家自然也没有了,“国”和“家”显然也是组合关系。而相反的,计算机和它的外设之间就是聚合关系,因为它们之间的关系相对松散,计算机没了,外设(例如U盘)还可以独立存在,还可以接在别的计算机上。在聚合关系中,部分可以独立于聚合而存在,部分的所有权也可以由几个聚合来共享,比如打印机就可以在办公室内被广大同事共用。
关联和聚合的区别主要在语义上,关联的两个对象之间一般是平等的,例如你是我的朋友,聚合则一般不是平等的,例如一个公司包含了很多员工,其实现上是差不多的。聚合和组合的区别则在语义和实现上都有差别,组合的两个对象之间其生命期有很大的关联,被组合的对象是在组合对象创建的同时或者创建之后创建,在组合对象销毁之前销毁。一般来说被组合对象不能脱离组合对象独立存在,而且也只能属于一个组合对象,例如一个文档的版本,必须依赖于文档的存在,也只能属于一个文档。聚合则不一样,被聚合的对象可以属于多个聚合对象,例如一个员工可能可以属于多个公司。
小结
本文说明了组合和聚合,以及两者之间的区别,后续会介绍依赖关系和泛化关系。希望各位能看完文章后,对组合和聚合有了一定的了解。