借鉴资料:博客
类与类之间的关系
类与类之间的关系可以根据关系的强度依次分为以下五种:
依赖关系(Dependency)---关联关系(Association)---聚合(Aggregation)---组合(Composition)---泛化(Generalization)
1.依赖关系(Dependency)
依赖关系使用虚线加箭头表示,如下图所示:
这个例子可能不太好(Animal体内有Water,),换一个:
解释以下:Person 和 Computer之间是没有关系的,但是由于偶尔的需要,Person需要使用Computer,这时Person就依赖于Computer.
依赖关系是五种关系中耦合最小的一种关系。
类A要完成某个功能必须引用类B,则类A依赖类B。C#不建议双向依赖,也就是相互引用。
上述依赖关系在代码中的表现形式:这两个关系类都不会增加属性。
class Person
{
public:
Person()
{
}
};
class Computer
{
public:
Computer()
{
}
};
那么,Person类如何使用Computer类呢?有三种方式:
依赖关系的三种表现形式:
1.Computer类是public的,Person类可以调用它。
2.Computer类是Person类中某个方法的局部变量,则Person类可以调用它。
3.Computer类作为Person类中某个方法的参数或返回值。
代码如下:
//2.Computer类是Person类中某个方法的局部变量,则Person类可以调用它
#include<bits/stdc++.h>
using namespace std;
class Computer{
public:
Computer(){
}
};
class Person{
public:
Person(){
}
void Programing(){
Computer *computer = new Computer();
}
};
int main(){
}
【解释】
Person有一个Programing方法,Computer类作为该方法的变量来使用。
注意Computer类的生命周期,当Programing方法被调用的时候,才被实例化。
持有Computer类的是Person类的一个方法,而不是Person类,这点是最重要的。
//3.Computer类作为Person类中某个方法的参数或返回值。
#include<bits/stdc++.h>
using namespace std;
class Computer{
public:
Computer(){
}
};
class Person{
public:
Person(){
}
Computer *Programing(Computer *it){
return it;
}
};
int main(){
}
【解释】
Computer类被Person类的一个方法所持有,生命周期随着方法执行结束而结束。
在依赖关系中,必须使用这三种方法之一。
2.关联关系(Association)
关联关系是实线加箭头表示。表示类之间的关系比依赖要强。
例如,水和气候是关联的,表示如下:
在代码中的表现如下:
//关联 在Water类属性中增加了Climate类。
#include<bits/stdc++.h>
using namespace std;
class Climate{
public:
Climate(){
}
};
class Water{
public:
Climate *climate = new Climate();
Water(){
}
};
int main(){
}
可见,在Water类属性中增加了Climate类。
关联关系有单向关联、双向关联、自身关联、多维关联等等。其中后三个可以不加箭头。
单向关联:
双向关联:
自身关联:
多维关联:
关联和依赖的区别:
- 从类的属性是否增加的角度看:
发生依赖关系的两个类都不会增加属性。其中的一个类作为另一个类的方法的参数或者返回值,或者是某个方法的变量而已。
发生关联关系的两个类,其中的一个类成为另一个类的属性,而属性是一种更为紧密的耦合,更为长久的持有关系。
- 从关系的生命周期来看:
依赖关系是仅当类的方法被调用时而产生,伴随着方法的结束而结束了。
关联关系是当类实例化的时候即产生,当类销毁的时候,关系结束。相比依赖讲,关联关系的生存期更长。
3.聚合(Aggregation)
4.组合(Composition)
引用程杰的《大话设计模式》里举大那个大雁的例子 :
大雁喜欢热闹害怕孤独,所以它们一直过着群居的生活,这样就有了雁群,每一只大雁都有自己的雁群,每个雁群都有好多大雁,大雁与雁群的这种关系就可以称之为聚合。
另外每只大雁都有两只翅膀,大雁与雁翅的关系就叫做组合。
有此可见:
聚合的关系明显没有组合紧密,大雁不会因为它们的群主将雁群解散而无法生存;
而雁翅就无法脱离大雁而单独生存——组合关系的类具有相同的生命周期。
聚合关系图:
组合关系图:
在代码中表现如下:
//聚合
#include<bits/stdc++.h>
using namespace std;
class Goose{
public:
};
class GooseGroup{
public:
Goose *goose;
GooseGroup(Goose *g){
goose = g;
}
};
int main(){
}
//组合
#include<bits/stdc++.h>
using namespace std;
class Goose{
public:
};
class GooseGroup{
public:
Goose *goose;
GooseGroup(){
goose = new Goose();
}
};
int main(){
}
【解释】
这两种关系的区别是:
1.构造函数不同
- 聚合类的构造函数中包含另一个类的实例作为参数
因为构造函数中传递另一个类的实例,因此大雁类可以脱离雁群类独立存在。
- 组合类的构造函数包含另一个类的实例化
因为在构造函数中进行实例化,因此两者紧密耦合在一起,同生同灭,翅膀类不能脱离大雁类存在。
2.信息的封装性不同
在聚合关系中,客户端可以同时了解GooseGroup类和Goose类,因为他们是独立的。
在组合关系中,客户端只认识大雁类,根本不知道翅膀类的存在,因为翅膀类被严密地封装在大雁类中。
5.泛化(Generalization)
泛化是学术名称,通俗的来讲,通常包含类与类之间的继承关系和类与接口实现关系。
类与类之间的泛化
接口的实现