UML中的各种关系
各种关系
名称 | 英文名称 | 符号 | 描述 | 实现方法 | 耦合强度 | 举例 | 关键词 | 备注 |
依赖 | dependency | ![]() |
1.当类与类之间有使用关系 时就属于依赖关系;2.依赖 不具有“拥有关系”,而是 一种“相识关系”;3.一个 类的实现需要另一个类的协助 |
如果类A访问类B的属性或者方法, 或者类A负责实例化类B,具体地, 被依赖者B是依赖者A的:1.成员 函数返回值、2.形参、3.局部 变量、4.静态方法调用 |
★ | 学生使用电脑 驾驶员使用车 |
使用关系 | |
关联 | association | ![]() |
一种常识上的拥有关系,但 双方又在逻辑上各自独立 |
关联者的某数据成员是指向被关 联者的指针或引用 |
★★ | 老师和学生是 双向关联 |
拥有关系 has-a |
细分为:单向关联、 双向关联、 自身关联、多维关联 |
聚合 | aggregation | ![]() |
是整体与部分的关系,且部分 可脱离整体而单独存在 |
同“关联” | ★★★ | 汽车和轮胎 | 整体与部分 单独存在 contains-a |
|
组合 | composition | ![]() |
是整体与部分的关系,但部分 不能离开整体而单独存在 |
“整体类”的某数据成员存储 了“部分类”的实例 |
★★★★ | 人和头颅 | 整体与部分 不能单独存在 |
|
泛化 | generalization | ![]() |
类与类之间的继承关系,一般 与特殊的关系,is a |
类继承 | ★★★★★ | 动物和猫 | 一般与特殊 is-a |
|
实现 | implementation | ![]() |
类与接口之间的实现关系 | 接口实现 | ★★★★★ | 鸡和鸭都实现 下蛋接口 |
联系与区别
依赖与关联
- 实现不同:依赖者不会将被依赖者作为自己的数据成员,但关联会。
- 侧重点不同:依赖强调使用,关联强调拥有。
- 关系产生/结束时机不同:依赖关系是仅当使用关系发生(如类A的成员函数以类B的实例为参数)时而产生,伴随着使用结束而结束。关联关系当A中指向B的指针/引用被赋值时产生,当A的实例销毁时关系结束。
关联与聚合
- 聚合关系是关联关系的一种,是强的关联关系。
- 逻辑关系/层次不同:关联关系所涉及的两个类处在同一个层次上,而聚合关系中,两个类处于不同的层次上,一个代表整体,一个代表部分。
- 指向被关联/聚合者的指针/引用的初始化/赋值形式不同(这一点并非绝对):对于关联,通过A的成员函数( void A::setB(B *pB) )来为A中指向B的指针/引用赋值;对于聚合,通过带参的构造函数( A::A(B *pb) )来初始化A中指向B的指针/引用。
- 联和聚合在语法上无法区分,必须考察具体的逻辑关系。
聚合与组合
- 整体与部分的生命周期不同:对于聚合,整体与部分的生命周期相互独立;对于组合,整体与部分有相同的生命周期,其中代表整体的对象负责代表部分的对象的生命周期。
- 构造函数不同:聚合类的构造函数中包含另一个类的实例作为参数,组合类的构造函数包含另一个类的实例化。
- 信息的封装性不同:聚合关系中,客户端可以同时了解“整体类”与“部分类”;组合关系中,客户端只认识“整体类”,“部分类”被严密封装在“整体类中”,对客户端不可见。
举例说明
下图是设计模式中命令模式(Command Pattern)的UML类图和C++实现,其中代码“改编”自这个开源项目。不熟悉命令模式的读者请自行学习。


1 #include <iostream>
2
3 class Receiver
4 {
5 public:
6 void Action()
7 {
8 std::cout << "Receiver: execute action" << std::endl;
9 }
10 // ...
11 };
12
13 class Command
14 {
15 public:
16 virtual ~Command() {}
17 virtual void Execute() = 0;
18
19 protected:
20 Command() {}
21 };
22
23 class ConcreteCommand : public Command
24 {
25 public:
26 ConcreteCommand(Receiver *r) : receiver(r) {}
27
28 ~ConcreteCommand()
29 {
30 if (receiver)
31 {
32 delete receiver;
33 }
34 }
35
36 void Execute()
37 {
38 receiver->Action();
39 }
40
41 private:
42 Receiver *receiver;
43 };
44
45 class Invoker
46 {
47 public:
48 void SetCommand(Command *c)
49 {
50 command = c;
51 }
52
53 void ExecuteCommand()
54 {
55 if (command)
56 {
57 command->Execute();
58 }
59 }
60
61 private:
62 Command *command = nullptr;
63 };
64
65 int main()
66 {
67 ConcreteCommand command(new Receiver());
68
69 Invoker invoker;
70 invoker.SetCommand(&command);
71 invoker.ExecuteCommand();
72
73 return 0;
74 }
Command Pattern
下面结合代码进行分析:
- 依赖:这里的 main 函数相当于 Client , main 函数中仅仅创建并使用了 Receiver 、 ConcreteCommand 、 Invoker 的实例,相当于将它们的实例作为局部变量,因此 main 函数( Client )依赖了这三个类。
- 关联: Invoker 类中有指向 Command 或其子类的指针,该指针通过成员函数 void SetCommand(Command *c) 被赋值,因此 Invoker 关联了 Command 。
- 聚合: ConcreteCommand 类中有指向 Receiver 的指针,该指针通过构造函数 ConcreteCommand(Receiver *r) 在 ConcreteCommand 实例被创建的同时被初始化,因此,
ConcreteCommand
聚合了Receiver
。
需要特别说明的是,受GoF的《Design Patterns: Elements of Reusable Object-Oriented Software》误导,几乎所有资料的UML类图都将 Ivoker 和 Command 画成了聚合关系,而将 ConcreteCommand 和 Receiver 画成了关联关系(正好跟上图相反),这显然是不对的。理由如下:
- “绑定”关系的牢固性不同:
- Invoker 和 Command 通过 void Invoker::SetCommand(Command *c) 建立关系,并且,通过多次调用该函数,可以对 Invoker::command 这个成员变量赋不同的值,即 Invoker 实例可以“绑定”不同的 Command 实例,这种“绑定”是不稳定的,可更换的。
- 反观 ConcreteCommand ,它通过自身的构造函数 ConcreteCommand(Receiver *r) 与 Receiver 实例“绑定”,并且 ConcreteCommand 实例一旦构造完成,它所“绑定”的 Receiver 实例就不能换成其它 Receiver 实例了。显然, ConcreteCommand 和 Receiver 之间的“绑定”关系,要比 Invoker 和 Command 之间的“绑定”关系牢固得多。
- 关系层次不同:
- 普通成员函数 void Invoker::SetCommand(Command *c) 暗示 Invoker 和 Command 之间是同一个层次上的“平等”关系。
- 构造函数 ConcreteCommand(Receiver *r) 暗示 ConcreteCommand 和 Receiver 之间是整体与部分的关系。
参考
UML中的各种关系的更多相关文章
- 软件设计之UML—UML中的六大关系
一.UML中的六大关系 在UML类图中,常见的有以下几种关系: 泛化(Generalization), 实现(Realization),关联(Association),聚合(Aggregation), ...
- [转] UML中的六大关系
UML中的六大关系 转自:https://www.cnblogs.com/hoojo/p/uml_design.html 在UML类图中,常见的有以下几种关系: 泛化(Generalization), ...
- UML中的依赖关系
UML中的五种关系和设计模式中的代码实现. 又重新听了一遍UML中的关系.感觉又是收获很大. UML中的关系有依赖,关联(聚合,组合),泛化(也叫继承),实现 现在一个一个的来实现: 一:依赖 依赖关 ...
- UML中的六大关系(转)
UML定义的关系主要有六种:依赖.继承.关联.实现.聚合和组合.这些类间关系的理解和使用是掌握和应用UML的关键,而也就是这几种关系,往往会让初学者迷惑.这里给出这六种主要UML关系的说明和类图描述, ...
- uml中定义的关系详细详解
uml定义的关系主要有六种:依赖.类属.关联.实现.聚合和组合.下面对其定义和表示方法逐一说明. 依赖(Dependency):元素A的变化会影响元素B,但反之不成立,那么B和A的关系是依赖关系,B依 ...
- UML中的六大关系
转自:http://www.cnblogs.com/shengtianlong/archive/2010/10/23/1858953.html UML定义的关系主要有六种:依赖.类属.关联.实现.聚合 ...
- UML中的六种关系的比较与学习
通过不断的学习并绘制UML图,整个画图的过程中深刻体会到其核心部分还是理解事物之间的关系,总结六大关系来深入学习,主要关系有六种:继承.实现.依赖.关联.聚合.组合. 区别于联系: 1 ...
- UML解惑:图说UML中的六大关系--转
UML定义的关系主要有六种:依赖.类属.关联.实现.聚合和组合.这些类间关系的理解和使用是掌握和应用UML的关键,而也就是这几种关系,往往会让初学者迷惑.这里给出这六种主要UML关系的说明和类图描述, ...
- UML解惑:图说UML中的六大关系
UML定义的关系主要有六种:依赖.类属.关联.实现.聚合和组合.这些类间关系的理解和使用是掌握和应用UML的关键,而也就是这几种关系,往往会让初学者迷惑.这里给出这六种主要UML关系的说明和类图描述, ...
- UML中的六种关系
设计模式是一种对于面向对象语言(C#,C++,Java)的高级应用.其思维体现出的是真正的代码设计.每一种模式都堪称巧妙!但基于各种设计模式,这里少不了基本的类图设计,本文简要列出6种关系,及相关的例 ...
随机推荐
- 一站式解决方案 :OFD电子证照生成
前言 证照的电子化是一个趋势:可以预计,未来几年内,绝大部分证照都会电子化.电子证照的种类越来越多,应用场景也复杂多样:这就给电子证照规范的制定.电子证照的生成提出了更高的要求.电子证照采用的格式有两 ...
- 关于win1124h2不兼容HCL
Windows 11 24H2与HCL不兼容的问题较为复杂,以下是几种常见的解决办法: 回退系统版本 如果是在更新到Windows 11 24H2的10天内发现HCL不兼容,可以使用系统自带的回退功能 ...
- winform 引用AForge调用摄像头拍照
Nuget安装这个2个: AForge.Controls; AForge.Video.DirectShow; code: namespace WindowsFormsApp1 { partial cl ...
- Spring Security 基于JWT的单点登陆(SSO)开发及原理解析
JDK1.8Spring boot 2.xSpring Security 5.x 单点登录(Single Sign On),简称为SSO,是目前比较流行的企业业务整合的解决方案之一. SSO的定义是在 ...
- CyclicBarrier底层实现和原理
1.CyclicBarrier 字面意思是可循环(Cyclic)使用的屏障(Barrier).它要做的事情是让一组线程到达一个屏障(同步点)时被阻塞,直到最后一个线程到达屏障时候,屏障才会开门.所有被 ...
- 计算困难假设(Computational hardness assumption)
以下内容翻译自:维基 介绍 在计算复杂性理论中,计算困难假设是一个特定问题无法得到有效解决的假设(有效通常指"在多项式时间内").目前还不知道如何证明其困难性.同时,我们可以将一个 ...
- linux:搭建 WordPress 个人站点
参考:链接 介绍 WordPress 是一款使用 PHP 语言开发的博客平台,您可使用通过 WordPress 搭建属于个人的博客平台.本文以 CentOS 6.5 操作系统为例,手动搭建 WordP ...
- linux下自建NAS教程
NAS,英文全名Network Attached Storage,翻译过来是:网络附接存储. 引用维基百科定义 网络附接存储(英语:Network Attached Storage,缩写:NAS)[1 ...
- webstorm前端vue项目安装依赖包总结
npm install提示错误信息,与node.js版本有关.以下是用到的一些命令行参数: 1.清除npm的缓存:npm cache clean --force 2.设置npm下载镜像:npm con ...
- Prometheus修改默认数据存储时间
Prometheus修改默认数据存储时间 Prometheus 的数据存储时间是通过命令行参数 --storage.tsdb.retention.time 来设置的.这个参数指定了 Prometheu ...