今天我们来看一下UML图中的类图。
先上一张图,通过这张图来解释类图。
面向对象设计一直以来有一句特别经典的话“高内聚,低耦合”,想要搞明白这句话之前必须先搞明白关系
在探讨这个类图之前,首先我们得搞清楚类图中常见的关系:泛化(Generalization), 实现(Realization), 关联(Association), 聚合(Aggregation), 组合(Composition), 依赖(Dependency)
1.泛化(Generalization)
泛化是一种继承关系,例如上图中的鸟继承动物,大雁,鸭子,企鹅都是鸟的子类,唐老鸭是鸭子的子类。
表示方式:带三角箭头的实线,箭头指向父类
2. 实现(Realization)
实现是类和接口的关系,表示类实现接口的所有特征和行为。例如上图中的大雁实现飞翔接口,唐老鸭实现讲话接口。
表示方式:带三角箭头的虚线,箭头指向接口。
3. 关联(Association)
【关联关系】:是一种拥有的关系, 它使一个类知道另一个类的属性和方法;如:老师与学生,丈夫与妻子。例如:企鹅关联气候
关联可以是双向的,也可以是单向的。双向的关联可以有两个箭头或者没有箭头,单向的关联有一个箭头。
【代码体现】:成员变量
【箭头及指向】:带普通箭头(或实心三角形箭头)的实心线,指向被拥有者
4. 聚合(Aggregation)
【聚合关系】:是整体与部分的关系, 且部分可以离开整体而单独存在. 如车和轮胎是整体和部分的关系, 轮胎离开车仍然可以存在.例如上图中的大雁和燕群,燕子离开燕群也可以生活。
聚合关系是关联关系的一种,是强的关联关系;关联和聚合在语法上无法区分,必须考察具体的逻辑关系。
【代码体现】:成员变量
【箭头及指向】:带空心菱形的实心线,菱形指向整体
5. 组合(Composition)
【组合关系】:是整体与部分的关系, 但部分不能离开整体而单独存在. 如公司和部门是整体和部分的关系, 没有公司就不存在部门.例如上图上的鸟和翅膀的关系,两者的生命周期相同,只要鸟死亡也就意味着翅膀将要腐烂(死亡)
组合关系是关联关系的一种,是比聚合关系还要强的关系,它要求普通的聚合关系中代表整体的对象负责代表部分的对象的生命周期
【代码体现】:成员变量
【箭头及指向】:带实心菱形的实线,菱形指向整体
6. 依赖(Dependency)
【依赖关系】:是一种使用的关系,假设A类的变化引起了B类的变化,则说名B类依赖于A类, 即一个类的实现需要另一个类的协助, 所以要尽量不使用双向的互相依赖.
例如上图中的动物依赖氧气和水。
【代码表现】:局部变量、方法的参数或者对静态方法的调用
【箭头及指向】:带箭头的虚线,指向被使用者
各种关系的强弱顺序:
泛化 = 实现 > 组合 > 聚合 > 关联 > 依赖
聚合跟组合其实都属于关联 只不过它们是两种特殊的关联 因为本是同根生 所以它们之间难免会有相似之处 下面让我们一起来看一下它们之间有何不同
1.聚合与组合
(1)聚合与组合都是一种结合关系,只是额外具有整体-部分的意涵。
(2)部件的生命周期不同
聚合关系中,整件不会拥有部件的生命周期,所以整件删除时,部件不会被删除。再者,多个整件可以共享同一个部件。
组合关系中,整件拥有部件的生命周期,所以整件删除时,部件一定会跟着删除。而且,多个整件不可以同时间共享同一个部件。
(3)聚合关系是“has-a”关系,组合关系是“contains-a”关系。
(4)组合和聚合是视问题域而定的,例如在关心汽车的领域里,轮胎是一定要组合在汽车类中的,因为它离开了汽车就没有意义了。但是在卖轮胎的店铺业务里,就算轮胎离开了汽车,它也是有意义的,这就可以用聚合了。
2.关联和聚合
(1)表现在代码层面,和关联关系是一致的,只能从语义级别来区分。
(2)关联和聚合的区别主要在语义上,关联的两个对象之间一般是平等的,例如你是我的朋友,聚合则一般不是平等的。
(3)关联是一种结构化的关系,指一种对象和另一种对象有联系。
3.关联和依赖
(1)关联关系中,体现的是两个类、或者类与接口之间语义级别的一种强依赖关系,比如我和我的朋友;这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的。
(2)依赖关系中,可以简单的理解,就是一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、临时性的、非常弱的,但是B类的变化会影响到A。
4.综合比较
这几种关系都是语义级别的,所以从代码层面并不能完全区分各种关系;但总的来说,后几种关系所表现的强弱程度依次为:
组合>聚合>关联>依赖;
代码示例:
燕群类
public class GooseGroup
{
public Goose goose;
public GooseGroup(Goose goose)
{
this.goose = goose;
}
}
大雁类:
public class Goose
{
public Wings wings;
public Goose()
{
wings=new Wings();
}
}
聚合关系的类里含有另一个类作为参数
雁群类(GooseGroup)的构造函数中要用到大雁(Goose)作为参数把值传进来 大雁类(Goose)可以脱离雁群类而独立存在
组合关系的类里含有另一个类的实例化
大雁类(Goose)在实例化之前 一定要先实例化翅膀类(Wings) 两个类紧密耦合在一起 它们有相同的生命周期 翅膀类(Wings)不可以脱离大雁类(Goose)而独立存在
在聚合关系中,客户端可以同时了解雁群类和大雁类,因为他们都是独立的
而在组合关系中,客户端只认识大雁类,根本就不知道翅膀类的存在,因为翅膀类被严密的封装在大雁类中。