借鉴资料:博客
类与类之间的关系
类与类之间的关系可以根据关系的强度依次分为以下五种:
依赖关系(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)
泛化是学术名称,通俗的来讲,通常包含类与类之间的继承关系和类与接口实现关系。
类与类之间的泛化
接口的实现