终于分清楚依赖泛化实现关联聚合和组合了

Posted 默辨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了终于分清楚依赖泛化实现关联聚合和组合了相关的知识,希望对你有一定的参考价值。




该篇博文根据原尚硅谷讲师韩顺平老师的课程——尚硅谷Java设计模式(图解+框架源码剖析)整理而出



UML图之类图

1、概述

1)UML——Unified modeling language UML (统一建模语言),是一种用于软件系统分析和设计的语言工具,它用于帮助软件开发人员进行思考和记录思路的结果

2)UML 本身是一套符号的规定,就像数学符号和化学符号一样,这些符号用于描述软件模型中的各个元素(类、接口)和他们之间的关系,比如依赖、关联、泛化(继承)、实现、聚合、组合,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hrq5jyT7-1623923141800)(UML类图.assets/image-20210611193148258.png)]






2、类图

UML 图分类:

  1. 用例图(use case)

  2. 静态结构图:类图、对象图、包图、组件图、部署图

  3. 动态行为图:交互图(时序图与协作图)、状态图、活动图



类图:

  1. 用于描述系统中的类**(对象)本身的组成和类(对象)**之间的各种静态关系。

  2. 类之间的关系:依赖、泛化(继承)、实现、关联、聚合与组合。

  3. 类图简单举例

public class Person {
	private Integer id;
	private String name;

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public Integer getId() {
		return id;
	}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SqFaq6Rr-1623923141802)(UML类图.assets/image-20210612173421567.png)]






3、类图——依赖关系(Dependence)

类与类之间的连接。表示一个类依赖于另一类的定义。

表示一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、临时性的、非常弱的,但是B类的变化会影响到A

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sbyOzKUO-1623923141804)(UML类图.assets/image-20210612101004333.png)]

测试代码:

public class PersonDao {
}
public class IDCard {
}
public class Person {
}
public class Department {
}
public class PersonServiceBean {
    
	private PersonDao personDao;
    
	public void save(Person person) {
	}
    
	public IDCard getIDCard(Integer personid) {
		return null;
	}
    
	public void modify() {
		Department department = new Department();
	}
}

类关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EfhegBeX-1623923141807)(UML类图.assets/image-20210611201400278.png)]



类与类之间的联系往往包含以下几种方式:

  1. 类中用到了对方
  2. 类的成员属性
  3. 方法的返回类型
  4. 方法接收的形式参数
  5. 方法中使用到的类

当出现以上几种类型的关联关系时(只要用到对方),我们均可将它称之为依赖关系。在我们无法具体明确类与类之间的联系时(真实类所代表的含义之间的联系),说它们是依赖准没错的。后文出现的关联关系可以看作是依赖关系的强化版本。

图片中IDEA将PersonDao类和PersonServiceBean类识别为组合关系(使用黑色菱形箭头进行连接),当然我们使用带虚线的箭头表示也无伤大雅。





为什么这里IDEA会识别为组合关系呢?

网上也翻看了很多博客,但是都没有找到我觉得合理的解释,我且将它归咎为IDEA的问题。为什么这么说呢?我们首先要明确一个点就是UML图中类的关系是如何确立的,我们是不能够单纯的以代码结构来确认类与类之间的关系(不否认有的关系能通过代码看出来,如泛化和实现),而是应该根据具体类的含义来确认具体的类与类之间的联系。那对IDEA它能够分别出我每个实体类的真实含义吗?显然不能,所以得出是IDEA的问题。也不知道对不对,欢迎探讨。






4、类图——泛化关系(Generalization)

类比Java中的继承关系进行理解,是依赖关系的特例,常出现关键字extends。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iIkaOKRy-1623923141808)(UML类图.assets/image-20210612101025932.png)]

测试代码:

public class DaoSupport {
	public void save(Object entity){
	}
	public void delete(Object id){
	}
}
public class PersonServiceBean extends DaoSupport {
}

类关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mVMjteF9-1623923141808)(UML类图.assets/image-20210611202417288.png)]


总结:

  1. 泛化关系实际上就是继承关系
  2. 如果 A 类继承了 B 类,我们就说 A 和 B 存在泛化关系






5、类图——实现关系(Implementation)

类比Java的接口进行理解,在代码层面为一个类实现某个接口,使用关键字implements。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UJ8R6V0K-1623923141809)(UML类图.assets/image-20210612101115697.png)]

测试代码:

public interface PersonService {	public void delete(Integer id);}
public class PersonServiceBean implements PersonService {	public void delete(Integer id) {        	}}

类关系图:(IDEA生成的箭头变成是实心)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v5w7bHGB-1623923141809)(UML类图.assets/image-20210611204006402.png)]


总结:

  1. 实现关系实际上就是Java中接口的实现
  2. 如果 A 类实现了了 B 接口,我们就说 A 和 B 存在实现关系






6、类图——关联关系(Association)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j8DMfeyM-1623923141810)(UML类图.assets/image-20210612101137963.png)]

关联关系实际上就是类与类之间的联系,它是依赖关系的特例。这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的。如人和身份证是一种长期关系。

关联具有导航性:即双向关系或单向关系,表现在代码层面,为被关联类B以类属性的形式出现在关联类A中,也可能是关联类A引用了一个类型为被关联类B的全局变量

关联具有多重性:如“1”表示有且仅有一个;“0…”表示0个或者多个;“0,1”表示0个或者1个;“n…m”表示n到m个;“m…*”表示至少m个



单向一对一关系:

public class IDCard {}
public class Person {	private IDCard idCard;}

类关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bMPGMxFq-1623923141810)(UML类图.assets/image-20210611225715735.png)]




双向一对一关系:

public class IDCard {	private Person person;}
public class Person {	private IDCard idCard;}

类关系图:(单考虑关联关系时,应该去掉末端实心菱形)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FvA8TuRH-1623923141811)(UML类图.assets/image-20210611225451573.png)]



注意:

理论上这里是关联关系,但是IDEA生成的关系却是组合关系(实心菱形箭头)。其实这里要明白这些关系是根据什么确立的,即类图关系背后核心的逻辑是什么。

按照关系联系的强弱,关联关系是要强于依赖关系的。我们在区分不同类与类之间关系时的依据是参照具体类的含义,但IDEA是没有办法帮我们识别出我们创建的类所代表的含义的,即生成的UML类图是不能够保证一定准确的。(在依赖关系小节已经分析过)






7、类图——聚合关系(Aggregation)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PTCfs7rZ-1623923141811)(UML类图.assets/image-20210612101153386.png)]

聚合关系(Aggregation)表示的是整体和部分的关系,整体与部分可以分开。聚合关系是关联关系的特例,所以他具有关联的导航性与多重性。

如:一台电脑由键盘(keyboard)、显示器(monitor),鼠标等组成;组成电脑的各个配件是可以从电脑上分离出来的,使用带空心菱形的实线来表示:


测试代码:

public class Mouse {}
public class Monitor {}
public class Computer {	private Mouse mouse;	private Monitor monitor;	public void setMouse(Mouse mouse) {		this.mouse = mouse;	}	public void setMonitor(Monitor monitor) {		this.monitor = monitor;	}}

类关系图:(应将实心菱形换为空心菱形)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-264plcWr-1623923141811)(UML类图.assets/image-20210612172333202.png)]

图片中的关系是根据IDEA生成的,不准确的原因前面已经讲过,这里不再赘述。






8、类图——组合关系(Composition)

也是整体与部分的关系,但是整体与部分不可以分开。如人和人的头。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AUuQMSob-1623923141812)(UML类图.assets/image-20210612101209602.png)]


测试代码1:

public class Head {}
public class IDCard {}
public class Person {	private IDCard card;	private Head head = new Head();}

类关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FKmnHbWz-1623923141812)(UML类图.assets/image-20210612172606760.png)]


补充:

由代码可得 Head 和 Person 就是组合,IDCard 和 Person 是聚合。但是能否一定说Person和IDCard没有组合关系呢(本例中已有信息所展示的是聚合),其实是不能的。如果在我们的程序中Person实体类中定义了对IDCard进行级联删除,即删除Person时连同IDCard一起删除,那么我们就可以认为IDCard和Person就是组合关系。



测试代码2:

public class Mouse {}
public class Moniter {}
public class Computer {	private Mouse mouse = new Mouse(); // 该种写法,在某种程度上就说明,鼠标和 computer 不能分离	private Moniter moniter = new Moniter();// 该种写法,在某种程度上就说明,显示器和 Computer 不能分离}
// 类的另一种写法public class Computer2 {	private Mouse mouse;	private Moniter moniter;	public Computer2() {		mouse = new Mouse();		moniter = new Moniter();	}}

类关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y0NH8vm0-1623923141813)(UML类图.assets/image-20210612172650729.png)]



总结:

根据类的写法我们不难看出,当我们实例化Computer类或Computer2类时,对应的Mouse类和Moniter类也会被实例化,当Computer类或Computer2类被垃圾回收时,对应的Mouse类和Moniter类也会被回收,即有一种同生共死的感觉。我们将这种关系就称之为组合关系。






9、总结

六种关联关系,我们可以分为两拨进行理解。

泛化实现在代码层面可以根据关键字(extends、implements)进行区分,只要记住这个点一般不会和其他四个搞混淆。

剩下的四个分别是,依赖、关联、聚合、组合,它们由弱到强关系是: 没关系 > 依赖 > 关联 > 聚合 > 组合。



依赖和关联:两者主要是程度上的强弱。如人和船、飞机和电视,在业务场景中它们会有一个微弱的联系;人和身份证、大雁和雁群,在业务场景中它们的联系是要明显高于前者。

依赖和聚合:聚合属于关联的特例,它的程度比关联更更强

依赖和组合:组合属于关联的特例,它的程度必关联更更更强

关联和聚合:如果两个类是关联关系,那么它们是能够出现相互嵌套的关系的,如A中包含B,B中再包含A。但是聚合是部分和整体的关系,不能出现这种嵌套关系。如老师和学生,老师可以有很多学生,一个学生也可以拥有很多老师(多对多),所以他们就是关联关系。

关联和组合:区别方法与聚合类似,处于关联关系的两个类是可以包含嵌套关系的,组合只能是部分和整体的关系。,

聚合和组合:部分和整体之间的关系,如果部分能够独立于整体就是聚合,如果整体的生命周期结束部分的生命周期也结束那就是组合。如人和身份证、大雁和雁群就是聚合。人和头、大雁和翅膀,头和翅膀都必须依附与人和大雁,人和大雁生命周期的结束,那么头和翅膀也就结束了,所以它们的关系是组合。




注意,注意,注意:UML类图中类与类之间的关系不能简单的根据代码的写法来确定,还应该结合我们类所包含的真实意义(我最开始就想着根据代码来确定,结果发现不是这么回事)。根据真实意义来确定我们项类与类之间的关系,以此来确定代码结构。用我们的代码结构去反推类与类之间的关系,以此来确保我们程序代码设计是否正确。

以上是关于终于分清楚依赖泛化实现关联聚合和组合了的主要内容,如果未能解决你的问题,请参考以下文章

依赖泛化实现关联聚合组合

UML关系详解(泛化实现依赖关联组合聚合)

UML类关系(依赖,关联,聚合,组合,泛化,实现)

StarUML类图相关——关联聚合组合泛化依赖实现

UML中的6大关系(关联依赖聚合组合泛化实现)

UML-类图详解(依赖关联聚合组合泛化实现)