UML 类图及六大关系详解:继承、实现、依赖、关联、聚合、组合(Java+类图)

UML 类图及六大关系详解:继承、实现、依赖、关联、聚合、组合(Java+类图)

一、UML类图概述

在软件工程中,UML类图是描述系统静态结构的标准建模语言,而类之间的六种关系是理解系统设计意图的关键。无论是阅读现有系统源码,还是进行新功能的设计开发,准确识别类之间的关系都能显著提升代码质量和可维护性。

二、速览UML类图基础

类图其实很简单,主要包含三部分:

类名:这个类有什么属性:这个类有什么数据

方法:这个类能做什么

请添加图片描述


在所有类图形式中,常用的三种是:普通类、抽象类和接口。它们的表示方式略有差异,但结构一致。


1. 普通类(Class)

普通类是系统中最基本的构成单元,可以直接实例化。

  • Java代码示例

UML类图示例

在这里插入图片描述
publicclassStudent{privateint id;privateString name;publicintgetId(){return id;}publicvoidsetId(int id){this.id = id;}publicvoidstudy(){System.out.println("Studying...");}}

2. 抽象类(Abstract Class)

抽象类是一种不能被实例化的类,通常作为父类,被子类继承。它可以包含普通方法,也可以包含抽象方法

  • Java代码示例

UML类图示例

在这里插入图片描述
publicabstractclassPerson{protectedString name;protectedint age;publicvoidspeak(){System.out.println("Person speaking...");}publicabstractvoidwork();}

3. 接口(Interface)

接口表示一组行为能力,是一种 完全抽象的类型。接口不包含实现,只规定方法签名。从 JDK 8 开始,接口可以包含普通方法(default 方法,static 方法)

  • Java代码示例

UML类图示例

在这里插入图片描述


除了上图中常见的 <<interface>> 类风格画法外,UML 还允许使用更简洁的 棒棒糖符号(Lollipop Notation) 来表示接口:

在这里插入图片描述
publicinterfaceMovable{voidmove();}

UML类图不仅有这三类,还包括

  • 枚举(Enum)
  • 泛型类
  • 模板类(Template Class)
  • 元类(Meta Class)

但使用频率远不如普通类抽象类接口,因此本篇只介绍最常见的三种即可


4. UML类图中的表示规范(补充)

(1) 抽象方法与抽象类的表示

抽象方法的标准表示方式是在类图中将操作的名称以斜体显示。
根据 UML 2.5.1 规范第 9.6.4 节(Operations Notation):

“An abstract operation or property is denoted by writing the name of the operation or property in italics.”

规范明确指出需要将操作的名称以斜体表示。在实际应用中,整个操作签名(包括方法名、参数和返回类型)通常以斜体显示,以保持视觉一致性。
说明:抽象方法优先以斜体表示,但也可以在操作签名后添加 {abstract} 注解。

抽象类的名称同样优先以斜体显示。根据 UML 2.5.1 规范第 9.2.4.1 节(Classifier Notation):

“The name of an abstract Classifier is shown in italics, where permitted by the font in use.”

作为备选或补充,可以在类名后或下方使用文本注解 {abstract},即:

“Alternatively or in addition, an abstract Classifier may be shown using the textual annotation {abstract} after or below its name.”

说明:文献写 {abstract} 是规范允许的文本注解,实际绘图中通常用刻板印象 <<abstract>>。类名斜体和 {abstract}/<<abstract>> 都表示抽象类。


(2) 静态方法与构造方法的表示

静态方法的标准表示方式是将特征名称(包括方法名、参数和返回类型)整体下划线
根据 UML 2.5.1 规范第 9.4.4 节(Static Features Notation):

“Static features are underlined in the compartments in which they appear.”

下划线覆盖整个特征名称,而不是仅在方法名前添加下划线前缀。
作为备选,可以在操作签名后添加 {static} 关键字,即:

“An Operation may be specified as static. This is shown by writing {static} after the Operation signature.”

关于构造方法,UML 规范中没有强制要求在类图中显示构造方法。
通常情况下,默认的无参数构造方法可以省略显示,因为它在大多数编程语言中是隐式存在的。
只有当构造方法具有特殊参数、多个重载形式或在设计中具有重要意义时,才需要在类图中明确表示。


(3) 接口的表示方式

接口的表示必须在名称上方标注关键字 «interface»
根据 UML 2.5.1 规范第 10.4.4 节(Interface Notation):

“An Interface may be designated using the default notation for Classifier with the keyword «interface».”

仅通过斜体接口名称而不添加 «interface» 关键字不能明确表示接口,因为这无法与抽象类有效区分。

接口有两种主要的表示方式:

  • 分类器矩形表示法
    • 在名称上方标注 «interface» 关键字
    • 可以显示接口的所有操作
  • 棒棒糖(Lollipop)表示法
    • 接口表示为一个圆圈(球体),通常称为棒棒糖
    • 圆圈旁标注接口名称
    • 在棒棒糖表示法中,接口通常不列出具体操作,而是通过实线连接到实现该接口的分类器

接口名称可以选择性地以斜体显示,以强调其抽象性质,但这不是必需的,因为接口的抽象性主要通过 «interface» 关键字来标识。


(4) 可见性的表示

对于具有包可见性(default/package visibility)的特征,可以使用符号 ~ 来明确表示可见性,也可以省略可见性符号。
在 UML 规范中,省略可见性符号表示该特征具有包可见性,因此对于包可见性的特征,既可以明确写出 ~,也可以不写任何可见性符号,两者含义相同


三、六大关系详解

在 UML 类图中,类与类之间最常见的关系一共有 六种。每种关系都表示不同程度的“耦合”或“依赖”,从最弱到最强关系如下:

1. 依赖(Dependency)

  • 含义:A 用一下 B,比如方法参数方法返回值方法局部变量使用到了B
  • Java代码示例

UML类图示例

在这里插入图片描述

图形表示:虚线+箭头 由依赖者指向被依赖者

在这里插入图片描述
classPrinter{voidprint(String content){System.out.println(content);}}classDocument{String text;Document(String text){this.text = text;}StringgetText(){return text;}}classLogger{voidlog(String msg){System.out.println("Log: "+ msg);}}classOffice{DocumentprocessDocument(Document doc,Printer printer){// 方法参数依赖 Printer 和 DocumentnewLogger().log("Processing document");// 局部变量依赖 Logger printer.print(doc.getText());returnnewDocument("Processed: "+ doc.getText());// 返回值依赖 Document}}

如果是双向依赖的情况,首尾连接处需画两个箭头,但是这种情况极其少见且不推荐


2. 关联(Association)

  • 含义:A 和 B 有长期的关系,A 拥有 B 的引用(如成员变量),生命周期独立
  • Java代码示例

UML类图示例

在这里插入图片描述

图形表示:实线+箭头 由关联类指向被关联类

在这里插入图片描述
classAddress{String city;Address(String city){this.city = city;}}classPerson{Address address;// Person 持有 Address}

有时会存在特殊的双向关联情况:类 A 持有类 B 的引用,同时类 B 也持有类 A 的引用(如下)

  • Java代码示例

UML类图示例(也可画双向箭头)

在这里插入图片描述
classPerson{Address address;// Person 持有 Address}classAddress{Person person;// Address 持有 Person}

接下来会介绍 聚合 (Aggregation) 和 组合 (Composition)
需要说明的是:聚合组合 关系实际上是特殊的 关联 关系

关联(Association) ← 最宽泛├─ 聚合(Aggregation) ← 整体-部分,部分可独立
└─ 组合(Composition) ← 整体-部分,部分不可独立

聚合和组合一定是关联关系,但是关联不一定是聚合或组合关系

3. 聚合(Aggregation)

  • 含义:A 拥有 B 的引用(如成员变量),B 可以独立存在,生命周期相互独立
  • Java代码示例

UML类图示例

在这里插入图片描述

图形表示:实线 + 空心菱形 由部分指向整体

在这里插入图片描述
classStudent{String name;Student(String name){this.name = name;}}classSchool{List<Student> students;// 学校聚合学生voidaddStudent(Student s){if(students ==null) students =newArrayList<>(); students.add(s);}}// === 为什么这是“聚合”? ===// 1. Student 对象不是 School 创建的,而是外部传进来的。// 2. Student 即使不属于 School 也能单独存在(比如学生可以没有学校,也能作为对象存在)。// 3. School 只是“拥有学生列表”,一种“整体-部分但不强绑定”的关系。// 因此:学生属于学校,但学生可以独立存在 → 这是“聚合”。

4. 组合(Composition)

  • 含义:A 拥有 B 的引用(如成员变量),B 随 A 的生命周期消失,无法独立存在
  • Java代码示例

UML类图示例

在这里插入图片描述

图形表示:实线 + 实心菱形 由部分指向整体

在这里插入图片描述
classEngine{Engine(){System.out.println("Engine created");}}classCar{privateEngine engine =newEngine();// 引擎组合在汽车中Car(){System.out.println("Car created");}}// === 为什么这是“组合”? ===// 1. Engine 是 Car 自己在内部创建的,而不是外部传进来的。// 2. Engine 的存在完全依赖 Car,脱离汽车就没有意义(比如单独的引擎对象没有用途)。// 3. Car 和 Engine 是“整体-部分中最紧密”的关系:汽车创建,引擎就被创建。// 因此:部分(Engine)不能脱离整体(Car) → 这是“组合”。

提醒:需要注意的是,聚合和组合作为特殊的关联关系,在图形表示上分别在整体端(包含端)使用空心菱形实心菱形来标识。至于另一端(部分端)是否需要画箭头,则取决于是否需要明确表达导航方向
无论是聚合关系还是组合关系,从整体到部分的导航性都是关系本身固有的语义,因为整体都需要通过引用来访问部分对象。因此,在部分端画箭头可以更明确地表达这种导航关系,但由于这种导航性在聚合和组合关系的语义中都已经存在,画箭头都是可选的,可以根据需要明确导航方向时使用,不画箭头也是符合规范的。
这种处理方式在聚合关系和组合关系中是统一的,因为两种关系在导航性的语义上具有相同的特性:整体都需要通过某种引用机制来访问其组成部分,无论这种拥有关系是弱的聚合关系还是强的组合关系。
在 UML 中 依赖(Dependency)关联/组合/聚合(Association/Composition/Aggregation) 是完全不同的两类关系,判断规则也完全不一样。
依赖关系看的是“使用”:
只要一个类在代码里出现过另一个类型的名字(包括变量类型、参数类型、返回值、new 的右边),就表示它依赖该类型。依赖是最弱的关系,属于“用到就算”。
组合/聚合看的是“结构”:
它们映射的是类的内部组成关系,因此只根据**成员变量的声明类型(左边)**来判断,不看 new 时实际创建的子类。因为 UML 描述的是静态设计结构,而不是运行时对象。

5. 泛化(Generalization)

  • 含义:子类继承父类
  • Java代码示例

UML类图示例

在这里插入图片描述

图形表示:实线+空心三角箭头 由子类指向父类

在这里插入图片描述
classAnimanl{}classDogextendsAnimal{}classCatextendsAnimal{}

6. 实现(Realization)

  • 含义:类实现接口
  • Java代码示例

UML类图示例

在这里插入图片描述

图形表示:虚线+空心三角箭头 由实现类指向接口

在这里插入图片描述
interfaceRunnable{}classTaskimplementsRunnable{}

四、总结

在 UML 类图中,六种关系从 弱到强 的顺序通常为:
依赖 → 关联 → 聚合 → 组合 → 泛化(继承) → 实现

画类图时没有硬性规定必须用越强越好,整体原则是尽量按真实业务关系选择最准确的那一种:

  • 能确定整体–部分,就不要只画关联,而应画聚合或组合
  • 能确定生命周期绑定,就画组合;不能确定则画聚合
  • 无法判断是否是整体–部分时,再画普通关联
  • 仅在方法中短暂使用到对方时,使用最弱的依赖

最后需要强调:
聚合与组合本质上都属于关联的更精确形式
一旦确认某关系是聚合/组合,就应该直接画它们,而不是退回画成普通关联
通过以上原则,就能让你的类图相对更加准确

Read more

免费部署openClaw龙虾机器人(经典)

免费部署openClaw龙虾机器人(经典)

前几天出了个免费玩龙虾的详细教程,很多小伙伴觉得不错,但是还有一些新手留言反馈内容不够详细,这次我将重新梳理一遍,做一期更细致的攻略,同时扩展补充配置好之后的推荐(我认为是必要)操作,争取一篇文章让大家可以收藏起来,随时全套参照复用。 先看效果测试 部署完成基础运行效果测试,你可以直接问clawdbot当前的模型: 1.Token平台准备 首先,还是准备好我们可以免费撸的API平台 这里我找到了两个可以免费使用的API,测试之后执行效率还可以,下面将分别进行细致流程拆解。 1.1 硅基流动获取ApiKey (相对免费方案 推荐) 硅基流动地址:https://cloud.siliconflow.cn/i/6T57VxS2 如果有账号的直接登录,没有的注册一个账号,这个认证就送16元,可以直接玩收费模型,真香。认证完成后在API秘钥地方新建秘钥。 硅基流动里面很多模型原来是免费的,有了16元注册礼,很多收费的模型也相当于免费用了,我体验一下了原来配置免费模型还能用,也是值得推荐的。建议使用截图的第一个模型体验一下,我一直用它。 1.2 推理时代

By Ne0inhk

Flutter 三方库 angular_bloc 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致响应、工业级的 AngularDart 与 BLoC 协同架构实战

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 angular_bloc 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致响应、工业级的 AngularDart 与 BLoC 协同架构实战 在鸿蒙(OpenHarmony)系统的桌面级协同(如分布式办公网页版)、后台管理终端或高度复杂的 Web 仪表盘开发中,如何将经典的 BLoC 状态管理应用于 AngularDart 环境?angular_bloc 为开发者提供了一套天衣无缝的组件化连接器。本文将实战演示其在鸿蒙 Web 生态中的深度应用。 前言 什么是 Angular BLoC?它是一套专门为 AngularDart 框架设计的 BLoC 实现。通过指令(Directives)和管道(Pipes),它实现了由于数据流变化触发的 UI

By Ne0inhk
n8n飞书webhook配置(飞书机器人、飞书bot、feishu bot)Crypto节点、js timestamp代码、Crypto node

n8n飞书webhook配置(飞书机器人、飞书bot、feishu bot)Crypto节点、js timestamp代码、Crypto node

自定义机器人使用指南 利用 n8n 打造飞书 RSS 推送机器人 文章目录 * 自定义机器人使用指南 * 注意事项 * 功能介绍 * 在群组中添加自定义机器人 * 操作步骤 * 邀请自定义机器人进群。 * - 进入目标群组,在群组右上角点击更多按钮,并点击 设置。 * - 在右侧 设置 界面,点击 群机器人。 * - 在 群机器人 界面点击 添加机器人。 * - 在 添加机器人 对话框,找到并点击 自定义机器人。 * - 设置自定义机器人的头像、名称与描述,并点击 添加。 * 获取自定义机器人的 webhook 地址,并点击 完成。 * 测试调用自定义机器人的 webhook 地址,向所在群组发送消息。 * -

By Ne0inhk
【AI】——SpringAI通过Ollama本地部署的Deepseek模型实现一个对话机器人(二)

【AI】——SpringAI通过Ollama本地部署的Deepseek模型实现一个对话机器人(二)

🎼个人主页:【Y小夜】 😎作者简介:一位双非学校的大三学生,编程爱好者, 专注于基础和实战分享,欢迎私信咨询! 🎆入门专栏:🎇【MySQL,Javaweb,Rust,python】 🎈热门专栏:🎊【Springboot,Redis,Springsecurity,Docker,AI】  感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持!❤️ 目录 🎈Java调用Deepseek  🍕下载Deepseek模型  🍕本地测试  🍕Java调用模型 🎈构建数据库  🍕增强检索RAG  🍕向量数据库  🍕Springboot集成pgvector 🎈chatpdf 🎈function call调用自定义函数 🎈多模态能力 🎈Java调用Deepseek 本地没有安装Ollama、Docker,openwebUI,可以先学习一下这篇文章:【AI】——结合Ollama、Open WebUI和Docker本地部署可视化AI大语言模型_ollma+本地大模型+open web ui-ZEEKLOG博客

By Ne0inhk