终于分清楚依赖泛化实现关联聚合和组合了
Posted 默辨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了终于分清楚依赖泛化实现关联聚合和组合了相关的知识,希望对你有一定的参考价值。
文章目录
该篇博文根据原尚硅谷讲师韩顺平老师的课程——尚硅谷Java设计模式(图解+框架源码剖析)整理而出
UML图之类图
1、概述
1)UML——Unified modeling language UML (统一建模语言),是一种用于软件系统分析和设计的语言工具,它用于帮助软件开发人员进行思考和记录思路的结果
2)UML 本身是一套符号的规定,就像数学符号和化学符号一样,这些符号用于描述软件模型中的各个元素(类、接口)和他们之间的关系,比如依赖、关联、泛化(继承)、实现、聚合、组合,如下图:
2、类图
UML 图分类:
-
用例图(use case)
-
静态结构图:类图、对象图、包图、组件图、部署图
-
动态行为图:交互图(时序图与协作图)、状态图、活动图
类图:
-
用于描述系统中的类**(对象)本身的组成和类(对象)**之间的各种静态关系。
-
类之间的关系:依赖、泛化(继承)、实现、关联、聚合与组合。
-
类图简单举例
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;
}
}
3、类图——依赖关系(Dependence)
类与类之间的连接。表示一个类依赖于另一类的定义。
表示一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、临时性的、非常弱的,但是B类的变化会影响到A
测试代码:
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();
}
}
类关系图:
类与类之间的联系往往包含以下几种方式:
- 类中用到了对方
- 类的成员属性
- 方法的返回类型
- 方法接收的形式参数
- 方法中使用到的类
当出现以上几种类型的关联关系时(只要用到对方),我们均可将它称之为依赖关系。在我们无法具体明确类与类之间的联系时(真实类所代表的含义之间的联系),说它们是依赖准没错的。后文出现的关联关系可以看作是依赖关系的强化版本。
图片中IDEA将PersonDao类和PersonServiceBean类识别为组合关系(使用黑色菱形箭头进行连接),当然我们使用带虚线的箭头表示也无伤大雅。
为什么这里IDEA会识别为组合关系呢?
网上也翻看了很多博客,但是都没有找到我觉得合理的解释,我且将它归咎为IDEA的问题。为什么这么说呢?我们首先要明确一个点就是UML图中类的关系是如何确立的,我们是不能够单纯的以代码结构来确认类与类之间的关系(不否认有的关系能通过代码看出来,如泛化和实现),而是应该根据具体类的含义来确认具体的类与类之间的联系。那对IDEA它能够分别出我每个实体类的真实含义吗?显然不能,所以得出是IDEA的问题。也不知道对不对,欢迎探讨。
4、类图——泛化关系(Generalization)
类比Java中的继承关系进行理解,是依赖关系的特例,常出现关键字extends。
测试代码:
public class DaoSupport {
public void save(Object entity){
}
public void delete(Object id){
}
}
public class PersonServiceBean extends DaoSupport {
}
类关系图:
总结:
- 泛化关系实际上就是继承关系
- 如果 A 类继承了 B 类,我们就说 A 和 B 存在泛化关系
5、类图——实现关系(Implementation)
类比Java的接口进行理解,在代码层面为一个类实现某个接口,使用关键字implements。
测试代码:
public interface PersonService { public void delete(Integer id);}
public class PersonServiceBean implements PersonService { public void delete(Integer id) { }}
类关系图:(IDEA生成的箭头变成是实心)
总结:
- 实现关系实际上就是Java中接口的实现
- 如果 A 类实现了了 B 接口,我们就说 A 和 B 存在实现关系
6、类图——关联关系(Association)
关联关系实际上就是类与类之间的联系,它是依赖关系的特例。这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的。如人和身份证是一种长期关系。
关联具有导航性:即双向关系或单向关系,表现在代码层面,为被关联类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;}
类关系图:
双向一对一关系:
public class IDCard { private Person person;}
public class Person { private IDCard idCard;}
类关系图:(单考虑关联关系时,应该去掉末端实心菱形)
注意:
理论上这里是关联关系,但是IDEA生成的关系却是组合关系(实心菱形箭头)。其实这里要明白这些关系是根据什么确立的,即类图关系背后核心的逻辑是什么。
按照关系联系的强弱,关联关系是要强于依赖关系的。我们在区分不同类与类之间关系时的依据是参照具体类的含义,但IDEA是没有办法帮我们识别出我们创建的类所代表的含义的,即生成的UML类图是不能够保证一定准确的。(在依赖关系小节已经分析过)
7、类图——聚合关系(Aggregation)
聚合关系(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; }}
类关系图:(应将实心菱形换为空心菱形)
图片中的关系是根据IDEA生成的,不准确的原因前面已经讲过,这里不再赘述。
8、类图——组合关系(Composition)
也是整体与部分的关系,但是整体与部分不可以分开。如人和人的头。
测试代码1:
public class Head {}
public class IDCard {}
public class Person { private IDCard card; private Head head = new Head();}
类关系图:
补充:
由代码可得 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(); }}
类关系图:
总结:
根据类的写法我们不难看出,当我们实例化Computer类或Computer2类时,对应的Mouse类和Moniter类也会被实例化,当Computer类或Computer2类被垃圾回收时,对应的Mouse类和Moniter类也会被回收,即有一种同生共死的感觉。我们将这种关系就称之为组合关系。
9、总结
六种关联关系,我们可以分为两拨进行理解。
泛化和实现在代码层面可以根据关键字(extends、implements)进行区分,只要记住这个点一般不会和其他四个搞混淆。
剩下的四个分别是,依赖、关联、聚合、组合,它们由弱到强关系是: 没关系 > 依赖 > 关联 > 聚合 > 组合。
依赖和关联:两者主要是程度上的强弱。如人和船、飞机和电视,在业务场景中它们会有一个微弱的联系;人和身份证、大雁和雁群,在业务场景中它们的联系是要明显高于前者。
依赖和聚合:聚合属于关联的特例,它的程度比关联更更强
依赖和组合:组合属于关联的特例,它的程度必关联更更更强
关联和聚合:如果两个类是关联关系,那么它们是能够出现相互嵌套的关系的,如A中包含B,B中再包含A。但是聚合是部分和整体的关系,不能出现这种嵌套关系。如老师和学生,老师可以有很多学生,一个学生也可以拥有很多老师(多对多),所以他们就是关联关系。
关联和组合:区别方法与聚合类似,处于关联关系的两个类是可以包含嵌套关系的,组合只能是部分和整体的关系。,
聚合和组合:部分和整体之间的关系,如果部分能够独立于整体就是聚合,如果整体的生命周期结束部分的生命周期也结束那就是组合。如人和身份证、大雁和雁群就是聚合。人和头、大雁和翅膀,头和翅膀都必须依附与人和大雁,人和大雁生命周期的结束,那么头和翅膀也就结束了,所以它们的关系是组合。
注意,注意,注意:UML类图中类与类之间的关系不能简单的根据代码的写法来确定,还应该结合我们类所包含的真实意义(我最开始就想着根据代码来确定,结果发现不是这么回事)。根据真实意义来确定我们项类与类之间的关系,以此来确定代码结构。用我们的代码结构去反推类与类之间的关系,以此来确保我们程序代码设计是否正确。
以上是关于终于分清楚依赖泛化实现关联聚合和组合了的主要内容,如果未能解决你的问题,请参考以下文章