1、依赖关系(Dependency)
依赖关系是最常见的一种关系,是一种使用关系,即一个类的实现(或部分方法的实现)需要另外一个类的协助,所以应尽量避免双向的互相依赖关系;
对象 A 持有对象 B 的引用,对象 A 需要借助对象 B 的协助,假如 A 是一个类,那么 B 可以是局部变量,也可以是类中方法参数,或者对静态方法的调用;(对象 A 可以依赖B,也可以不依赖 B,用到了有 B 的部分方法就依赖了 B)
2、泛化关系(Generalization)
泛化关系是一种特殊的依赖关系,实际上也就是继承关系。A 类是 B 类和 C 类的父类,B、C有共用父类 A,说明 A 类是B、C类的泛化;
假如 B、C 继承了 A 类,A 就和 B、C 存在泛化关系;
3、实现关系(Implementation)
实现关系也是依赖关系的特例,是接口和实现接口的类之间的一种关系。
B 类实现了 A 类(接口),说明 B 实现了 A
4、关联关系(Association)
关联关系也是依赖关系的一种特例,表示类与类之间的关系;
如果一个类,类中有成员变量,且成员变量是一个类,则它们就构成关联关系了
关联关系具有:
-
导航性(即双向关系或单向关系);
-
关系具有多重性(一对多、多对多)
单向一对一关系,学生和校园卡(Student 和 StudentIDCard):
public class Student {
private StudentIDCard card; // 指向StudentIDCard
}
public class StudentIDCard {
// 注意:单向关系-这里并没有指向学生的引用
}
双向一对多关系,学生和校园卡(Student 和 StudentIDCard):
public class Student {
private StudentIDCard card; // 指向StudentIDCard
}
public class StudentIDCard {
private Student student; // 指向Student
}
5、聚合关系(Aggregation)
聚合关系表示的是整体和部分的关系,整体和部分可以分开;
A 类中使用了 B、C,且 B、C 可以从 A 类中分离出来,这种关系就是聚合关系;
在代码实现上,关联和聚合在语法上无法区分,必须考察具体的逻辑关系;
在代码实现聚合关系时,成员对象通常作为构造方法、Setter方法或业务方法的参数注入到整体对象中;
聚合关系是关联关系的一种特例,是一种强关联关系,因此聚合关系也具有关联关系的导航性和多重性;
- 导航性:聚合关系的导航性是指谁聚合谁的问题(把A 聚合到 B ,还是把 B 聚合到 A);
- 多重性:A 聚合了一个 B 是单聚合, 聚合了多个 B 是多聚合
/* 组合关系实例 */
public class Computer {
private Monitor monitor; // 显示器,可以和computer分离
private Host host; // 主机,可以和computer分离
public void setMonitor(Monitor monitor) {
this.monitor = monitor;
}
public void setHost(Host host) {
this.host= host;
}
}
6、组合关系(Composition)
组合是整体和部分的关系,但是和聚合关系不同的是,整体和部分不可以分开;(人和头的关系,如果一个人,他的头和人分开了,那这人也就没了)
组合也是关联关系,是比聚合关系还要强的一种组合关系,它要求普通的聚合关系中代表整体的对象管理代表部分的对象的生命周期;
在代码实现组合关系上,通常由在代表整体的类的构造方法中直接初始化代表部分的类(或者如下面代码展示那样);
学生时代忘记带作业,老师总是质问你怎么没有忘记把脑子带来,现在你可以反驳说 Student 和 HomeWork 是可以分开的聚合关系,而 Student 和 Head 是不可以分开的组合关系;
public class Computer {
/* 只要computer对象一创建起来, monitor 和 host也就跟着创建起来了
* 只要computer对象一销毁, monitor 和 host也就跟着销毁了
* 这样他们之间的关系就是组合关系,是共生共灭,不可分的
* ※ 注意这里和聚合的区别,聚合是通过setter和构造器初始化;
*/
private Monitor monitor = new Monitor(); // 显示器,不可和computer分离
private Host host = new Host(); // 主机,不可和computer分离
/* 一个类中的对象没有直接new一定表示不是组合关系
* 如,Student类中定义了的StudentCard没直接new,但是对SudentCard定义了级联删除
* 即删除Sudent时,同时删除SudentCard,那么Student和StudentCard是共生共灭的关系,
* 即也是组合关系
*/
}
再次举个栗子:
台式机的显示器部分和主机部分是可以分离的,是一种聚合关系;
一体机的主机部分和显示器是不可分离的,就是一种组合关系;
聚合和组合的区别
聚合关系:
- 整体和部分的关系,部分可以离开整体而存在,部分是整体的必需,但是部分的生命周期不归整体管理,部分是在调用(或创建)整体时new出再传入的;
- 整体有部分的引用
- 在整体构造器中或setter中传入部分的对象引用,再初始化整体的引用;部分先于整体产生(部分构造器传入),或者部分后于整体产生(部分setter方法传入);
组合关系:
- 整体和部分的关系,部分不能离开整体而存在。整体来管理部分的生命周期。
- 整体有部分的引用。
- 在构造器中初始化表示部分的对象或直接在整体中初始化部分;
当你忘带作业,老师常说你怎么没忘记把脑子带过来,这里的老师就是混淆了聚合和组合之间的关系
各种关系的耦合强度
泛化(继承 is-a) > 实现 > 组合 > 聚合 > 关联(has-a) > 依赖;
根据高内聚,低耦合原则,应该慎用继承:
如果A类和B类具有共同的代码,不应该通过继承把 A 类和 B 类的共同代码抽出来再继承,而应该通过组合关系来将共同代码抽出来;