浅谈UML中类之间的五种关系及其在代码中的表现形式
什么是类?
将某类东西归纳在一起,可以成为一个类。
类有很多种提炼角度,需要根据系统地目标、业务的场景,选取合适的角度对事物进行归纳。
什么是类图?
类图可能是UML中使用的最多的一种图。
和其他图一样,类图的基本语法并不复杂,可能一两天就能掌握,但是真正做到灵活的使用类图,可能需呀多年的功力。
类图是锻炼OOA(OO Analysis)和OOD(OO Design)思想的重要工具,有助于OOA、OOD思想的提升。
本篇博文,重点讲述类图中类与类之间的关系以及这种关系在代码中的实现形式。写作本文的原因是:网上关于UML类图的语法规则等的资料很多,但是涉及到关系在代码中实现形式的文章却很少。这是很容易理解的:UML语法规范什么的各种书上导出都是,网页上的也很多都是对各种语法规范的Copy;而类之间的关系反应到代码层面需要加入个人的理解。两者的区别是一个不需要动脑子,Copy过来就行,而另一个需要动脑子。
类与类之间的关系
类与类之间的关系可以根据关系的强度依次分为以下五种:
依赖关系(Dependency)---关联关系(Association)---聚合(Aggregation)---组合(Composition)---泛化(Generalization)
1.依赖关系(Dependency)
依赖关系使用虚线加箭头表示,如下图所示:
这个例子可能不太好(Animal体内有Water,),换一个:
解释以下:Person 和 Computer之间是没有关系的,但是由于偶尔的需要,Person需要使用Computer,这时Person就依赖于Computer.
依赖关系是五种关系中耦合最小的一种关系。
类A要完成某个功能必须引用类B,则类A依赖类B。C#不建议双向依赖,也就是相互引用。
上述依赖关系在代码中的表现形式:这两个关系类都不会增加属性。
那么,Person类如何使用Computer类呢?有三种方式:
依赖关系的三种表现形式:
1.Computer类是public的,Person类可以调用它。
2.Computer类是Person类中某个方法的局部变量,则Person类可以调用它。代码如下:
Person有一个Programing方法,Computer类作为该方法的变量来使用。
注意Computer类的生命周期,当Programing方法被调用的时候,才被实例化。
持有Computer类的是Person类的一个方法,而不是Person类,这点是最重要的。
3.Computer类作为Person类中某个方法的参数或返回值。
Computer类被Person类的一个方法所持有,生命周期随着方法执行结束而结束。
在依赖关系中,必须使用这三种方法之一。
2.关联关系(Association)
关联关系是实线加箭头表示。表示类之间的关系比依赖要强。
例如,水和气候是关联的,表示如下:
在代码中的表现如下:
可见,在Water类属性中增加了Climate类。
关联关系有单向关联、双向关联、自身关联、多维关联等等。其中后三个可以不加箭头。
单向关联:
双向关联:
自身关联:
多维关联:
关联和依赖的区别:
- 从类的属性是否增加的角度看:
发生依赖关系的两个类都不会增加属性。其中的一个类作为另一个类的方法的参数或者返回值,或者是某个方法的变量而已。
发生关联关系的两个类,其中的一个类成为另一个类的属性,而属性是一种更为紧密的耦合,更为长久的持有关系。
- 从关系的生命周期来看:
依赖关系是仅当类的方法被调用时而产生,伴随着方法的结束而结束了。
关联关系是当类实例化的时候即产生,当类销毁的时候,关系结束。相比依赖讲,关联关系的生存期更长。
3.聚合(Aggregation)
4.组合(Composition)
引用程杰的《大话设计模式》里举大那个大雁的例子 :
大雁喜欢热闹害怕孤独,所以它们一直过着群居的生活,这样就有了雁群,每一只大雁都有自己的雁群,每个雁群都有好多大雁,大雁与雁群的这种关系就可以称之为聚合。
另外每只大雁都有两只翅膀,大雁与雁翅的关系就叫做组合。
有此可见:
聚合的关系明显没有组合紧密,大雁不会因为它们的群主将雁群解散而无法生存;
而雁翅就无法脱离大雁而单独生存——组合关系的类具有相同的生命周期。
聚合关系图:
组合关系图:
在代码中表现如下:
这两种关系的区别是:
1.构造函数不同
- 聚合类的构造函数中包含另一个类的实例作为参数
因为构造函数中传递另一个类的实例,因此大雁类可以脱离雁群类独立存在。
- 组合类的构造函数包含另一个类的实例化
因为在构造函数中进行实例化,因此两者紧密耦合在一起,同生同灭,翅膀类不能脱离大雁类存在。
2.信息的封装性不同
在聚合关系中,客户端可以同时了解GooseGroup类和Goose类,因为他们是独立的。
在组合关系中,客户端只认识大雁类,根本不知道翅膀类的存在,因为翅膀类被严密地封装在大雁类中。
5.泛化(Generalization)
泛化是学术名称,通俗的来讲,通常包含类与类之间的继承关系和类与接口实现关系。
类与类之间的泛化
接口的实现
题外话:这种东西不可纸上谈兵,需要多多实践,实践-认识-再实践-再认识,不断地批评与自我批评。
理解这个就能看懂各种:设计模式(的UML描述),并且构建相应的C#代码!
欢迎批评指正,Wish it helps.