当前位置: 首页 > news >正文

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

一、UML类图概述

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

二、速览UML类图基础

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


1. 普通类(Class)

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

public class Student { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public void study() { System.out.println("Studying..."); } }

2. 抽象类(Abstract Class)

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

public abstract class Person { protected String name; protected int age; public void speak() { System.out.println("Person speaking..."); } public abstract void work(); }

3. 接口(Interface)

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

public interface Movable { void move(); }

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

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


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 initalics.”

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

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

“The name of an abstract Classifier is shown initalics, 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»关键字来标识。


(4) 可见性的表示

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


三、六大关系详解

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

1. 依赖(Dependency)

class Printer { void print(String content) { System.out.println(content); } } class Document { String text; Document(String text) { this.text = text; } String getText() { return text; } } class Logger { void log(String msg) { System.out.println("Log: " + msg); } } class Office { Document processDocument(Document doc, Printer printer) { // 方法参数依赖 Printer 和 Document new Logger().log("Processing document"); // 局部变量依赖 Logger printer.print(doc.getText()); return new Document("Processed: " + doc.getText()); // 返回值依赖 Document } }

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


2. 关联(Association)

class Address { String city; Address(String city) { this.city = city; } } class Person { Address address; // Person 持有 Address }

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

class Person { Address address; // Person 持有 Address } class Address { Person person; // Address 持有 Person }

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

关联(Association) ← 最宽泛

├─ 聚合(Aggregation) ← 整体-部分,部分可独立
└─ 组合(Composition) ← 整体-部分,部分不可独立

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


3. 聚合(Aggregation)

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

4. 组合(Composition)

class Engine { Engine() { System.out.println("Engine created"); } } class Car { private Engine engine = new Engine(); // 引擎组合在汽车中 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)

class Animanl { } class Dog extends Animal { } class Cat extends Animal { }

6. 实现(Realization)

interface Runnable { } class Task implements Runnable { }

java运行


四、总结

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

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

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

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

http://www.jsqmd.com/news/695487/

相关文章:

  • PostgreSQL libpq 由于整数回绕导致内存分配不足 HGVE-2025-E011
  • 机器学习中不平衡分类问题的采样策略与实践
  • 从‘踩坑’到‘填坑’:我的DVWA靶场搭建复盘,附PHPStudy 2024版最新配置要点
  • 2026年45L铝制行军锅技术解析与合规选型参考 - 优质品牌商家
  • 《AI大模型应用开发实战从入门到精通共60篇》009、LangChain之Model I/O:模型调用与输出解析
  • 新能源汽车专业升级,仿真教学软件科学布局指南
  • 录屏软件罢工?手把手教你用终端搞定MacOS Catalina的屏幕录制权限(附常见App包名查询)
  • 如何快速掌握Zotero翻译插件:提升研究效率的完整教程
  • 多模型接入统一API网关:通义、DeepSeek、智谱的兼容实践(附代码)
  • FreeSWITCH图形化界面实操:讯时FXO网关当‘中继’,分机打外线就这么配
  • 《AI大模型应用开发实战从入门到精通共60篇》010、LangChain之Prompt Templates:模板化你的提示词
  • Drawboard PDF免费版被砍后,我的7个工具位怎么分配最合理?(附颜色配置方案)
  • LSTM超参数调优实战:时间序列预测指南
  • 词嵌入技术解析:从Word2Vec到Transformer演进
  • 毕业答辩PPT还在熬夜肝?让百考通AI帮你把时间还给思考
  • 德国蔡司三维扫描仪国内授权经销商综合实力排行:德国蔡司三维扫描仪,德国蔡司三维蓝光扫描仪atos-q,排行一览! - 优质品牌商家
  • 终极MCP服务器:模块化架构与AI应用开发实战指南
  • 手把手教你用这5个脚本,榨干甲骨文免费服务器的网速潜力
  • 基于进化计算的多智能体协作框架:从原理到实践
  • 手把手搭建第一个企业级AI Agent:从零配置LangChain环境
  • 算法训练营第十三天|454.四数相加||
  • 8款古籍刻本书法字体分享,让你的新中式设计更有书卷气
  • LangChain框架解析:从RAG到智能代理的AI应用构建实战
  • Win10中文用户名导致Anaconda安装失败?保姆级修复与配置全流程(含软链接创建)
  • AI 应用安全加固:Scenario 自动化红队测试开源方案
  • 2026年q2不锈钢焊接加工厂:不锈钢折弯加工厂,不锈钢柜体加工厂,不锈钢橱柜定制加工,优选指南! - 优质品牌商家
  • 从QPushButton到QAction:一文掌握Qt中‘可切换’控件的完整使用手册(setCheckable/setChecked详解)
  • 从振荡波形到Python脚本:一次完整的运放偏置电流测量与数据分析实战
  • 轻量级容器Microverse:边缘计算与嵌入式AI的极简部署方案
  • 告别配置噩梦:用Vcpkg一键安装OpenCV 4.4.0到VS2019 C++项目