这六种是 UML 类图的核心关系,用来描述不同类(或接口)之间的关联逻辑,核心区别在于「关系强度、生命周期绑定、代码实现方式」。
先明确核心判断逻辑
所有关系按「关联强度从弱到强」排序:依赖(use-a) < 关联(has-a 弱) < 聚合(has-a 中) < 组合(has-a 强) < 实现(like-a) < 泛化(is-a)
- is-a:“是一种”(列如学生是一种人);
- has-a:“包含 / 拥有”(列如班级拥有学生);
- use-a:“临时使用”(列如学生用计算器做题);
- like-a:“像一种(实现接口)”(列如麻雀实现 “会飞” 接口)。
一、泛化(Generalization):is-a 继承关系
核心定义:「子类是父类的一种」,子类继承父类的属性和方法,可扩展自己的功能。
是最强的关系,子类和父类是 “本质同一类事物”。
生活类比:
- 学生(子类)是 人(父类)的一种;
- 猫(子类)是 动物(父类)的一种。
UML 图示:
- 实线 + 空心三角(三角指向「父类」)。
代码示例(Java):
java
// 父类:人
class Person {
String name;
void eat() {}
}
// 子类:学生(泛化自Person)
class Student extends Person { // extends 表明泛化
String studentId; // 子类扩展属性
void study() {} // 子类扩展方法
}
关键特点:
- 子类完全继承父类非私有成员,可重写父类方法;
- 父类变,子类可能受影响(耦合度高);
- 只能单继承(Java 中),但可多层继承(学生→人→生物)。
二、实现(Realization):like-a 接口实现
核心定义:「类实现接口的所有抽象方法」,接口定义 “行为规范”,类负责具体实现。
和泛化逻辑类似,但接口是 “行为契约”,不是具体类。
生活类比:
- 麻雀(类)实现 会飞(接口)的行为;
- 计算器(类)实现 可计算(接口)的行为。
UML 图示:
- 虚线 + 空心三角(三角指向「接口」)。
代码示例(Java):
java
// 接口:定义行为规范(无具体实现)
interface Flyable {
void fly(); // 抽象方法
}
// 类:实现接口(必须重写所有抽象方法)
class Sparrow implements Flyable { // implements 表明实现
@Override
public void fly() {
System.out.println("麻雀扇动翅膀飞");
}
}
关键特点:
- 接口只定义方法签名,不存属性(Java 8 + 可有默认方法);
- 一个类可实现多个接口(解耦,弥补单继承局限);
- 接口变,所有实现类都要改(契约约束)。
三、关联(Association):has-a 普通关联
核心定义:「两个类之间的 “一般联系”」,相互知道对方的存在,可双向或单向访问。
关系强度中等,是最常用的 “拥有” 关系,列如 “学生和老师”“用户和订单”。
生活类比:
- 学生 和 老师(学生知道自己的老师,老师知道自己的学生);
- 用户 和 订单(用户拥有多个订单,订单属于一个用户)。
UML 图示:
- 实线(双向关联无箭头;单向关联箭头指向「被关联方」);
- 可标注 “multiplicity”(数量关系,列如 1 对多、多对多)。
代码示例(Java):
java
// 订单类
class Order {
String orderId;
}
// 用户类(关联Order:用户拥有多个订单)
class User {
String userId;
List<Order> orders; // 成员变量引用Order,体现关联关系
}
关键特点:
- 关联是「长期持有」(用户和订单的关系会持续存在);
- 可双向关联(Order 类也加User user),或单向关联(只 User 有 Order,Order 不知道 User);
- 多对多关联需用中间类(列如 “学生和课程”,用 “选课表” 中间类)。
四、聚合(Aggregation):has-a 松散包含
核心定义:「整体包含部分,但部分可独立于整体存在」,是 “弱拥有” 关系。
整体和部分是 “组装关系”,部分能脱离整体单独存活。
生活类比:
- 班级(整体) 和 学生(部分):学生离开班级,依然是学生;
- 电脑(整体) 和 鼠标(部分):鼠标拆下来,还能给其他电脑用。
UML 图示:
- 空心菱形 + 实线(菱形在「整体端」,指向部分);
- 菱形是 “容器” 的象征,空心表明 “部分可独立”。
代码示例(Java):
java
// 部分类:学生
class Student {
String studentId;
}
// 整体类:班级(聚合学生)
class Class {
String className;
List<Student> students;
// 部分(学生)通过构造方法传入,不是在整体内部创建
public Class(List<Student> students) {
this.students = students;
}
}
// 使用:学生可先创建,再加入班级;班级解散,学生还在
Student s1 = new Student("1001");
List<Student> students = Arrays.asList(s1);
Class cls = new Class(students);
关键特点:
- 整体和部分「生命周期独立」(部分可提前创建,整体销毁后部分仍存在);
- 部分可被多个整体共享(一个学生可临时加入多个兴趣班);
- 代码上:部分通过 “外部传入”(构造器 /setter),不是整体内部new出来的。
五、组合(Composition):has-a 强依赖包含
核心定义:「整体包含部分,部分和整体同生共死」,是 “强拥有” 关系。
整体和部分是 “不可分割” 的,部分不能脱离整体单独存在。
生活类比:
- 人(整体) 和 心脏(部分):心脏离开人就失去意义,人死亡心脏也没用;
- 订单(整体) 和 订单明细(部分):订单明细不能脱离订单单独存在。
UML 图示:
- 实心菱形 + 实线(菱形在「整体端」,指向部分);
- 实心表明 “部分不可独立”。
代码示例(Java):
java
// 部分类:订单明细
class OrderItem {
String productName;
int quantity;
}
// 整体类:订单(组合订单明细)
class Order {
String orderId;
List<OrderItem> orderItems;
// 部分(订单明细)在整体内部创建,不是外部传入
public Order() {
this.orderItems = new ArrayList<>();
this.orderItems.add(new OrderItem()); // 整体创建部分
}
}
// 使用:创建订单时自动创建明细;删除订单,明细也跟着销毁
Order order = new Order();
关键特点:
- 整体和部分「生命周期绑定」(整体创建→部分创建,整体销毁→部分销毁);
- 部分只能属于一个整体(一个心脏不能同时属于两个人);
- 代码上:部分在整体的构造方法中new出来,外部无法直接创建部分并传入。
六、依赖(Dependency):use-a 临时使用
核心定义:「一个类临时使用另一个类的功能,不长期持有」,是最弱的关系。
列如 “学生用计算器做题”“工具类被其他类调用”,用完就断联。
生活类比:
- 学生(依赖方) 和 计算器(被依赖方):学生做题时用计算器,做完就不用了;
- 程序员(依赖方) 和 IDE(被依赖方):写代码时用 IDE,不写代码时 IDE 可关闭。
UML 图示:
- 虚线 + 箭头(箭头指向「被依赖方」,表明 “谁依赖谁”)。
代码示例(Java):
java
// 被依赖类:计算器
class Calculator {
static int add(int a, int b) { // 静态方法,方便临时调用
return a + b;
}
}
// 依赖方:学生
class Student {
// 依赖方式1:方法参数(临时传入)
void doHomework(Calculator calculator) {
int result = calculator.add(1, 2);
}
// 依赖方式2:局部变量(临时创建)
void doMath() {
Calculator calc = new Calculator(); // 局部变量,方法结束后销毁
calc.add(3, 4);
}
// 依赖方式3:静态方法调用(不用创建对象)
void doSum() {
Calculator.add(5, 6);
}
}
关键特点:
- 「临时使用,不长期持有」:被依赖类不会作为依赖类的成员变量(区别于关联);
- 依赖方变化不会影响被依赖方(列如学生换计算器,计算器本身不用改);
- 代码上:被依赖类以「方法参数、局部变量、静态方法调用」的形式出现,不是成员变量。
七、核心区别对比表(快速区分)
|
关系类型 |
核心关系 |
生命周期 |
代码表现(Java) |
关键判断点 |
|
泛化 |
is-a(继承) |
子类依赖父类 |
extends 关键字 |
子类是父类的一种 |
|
实现 |
like-a(接口) |
实现类依赖接口 |
implements 关键字 |
类实现接口的方法 |
|
关联 |
has-a(普通拥有) |
相互独立(长期持有) |
成员变量引用 |
两个类长期关联(列如用户 – 订单) |
|
聚合 |
has-a(松散包含) |
部分独立于整体 |
构造器 /setter 传入部分 |
部分可脱离整体存活(班级 – 学生) |
|
组合 |
has-a(强包含) |
部分与整体同生共死 |
整体内部 new 部分 |
部分不能脱离整体(人 – 心脏) |
|
依赖 |
use-a(临时使用) |
临时关联 |
方法参数 / 局部变量 / 静态调用 |
不长期持有,用完即断(学生 – 计算器) |
记忆:
- 是 “一种” 东西 → 泛化(继承);
- 要 “实现” 某个功能 → 实现(接口);
- 长期 “拥有” 另一个东西 → 关联;
- 松散 “包含”(可拆分) → 聚合;
- 紧密 “包含”(不可拆分) → 组合;
- 临时 “用一下” → 依赖。
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END














暂无评论内容