本设计模式系列通过UML类图基础、设计原则、设计模式详解和项目实战四个阶段,循序渐进地帮助读者掌握设计模式的核心思想与实际应用。从理论到实践,结合丰富的案例和主流框架分析,全面提升开发者的代码设计能力和软件开发水平。
我们在阅读开源项目时,总是希望能比较高效的整理清楚项目中的各个类之间的关系,那么有没有相应的工具能高效、简洁的表示清楚类关系呢?UML类图就是一个可以帮我们解决此类问题的工具或者方法。
1. 什么是类图?
- 定义:UML类图是一种静态结构图,用于描述系统的类、属性、操作(方法)以及类之间的关系。
- 核心价值:高效梳理代码结构,可视化类之间的交互,提升代码可读性和设计质量。
- 适用场景:阅读开源项目、系统设计、团队协作沟通。
2. 类图应用场景
- 开发阶段:设计系统架构,明确类职责。
- 文档化:为开源项目提供可维护的文档。
- 逆向工程:通过代码生成类图(如IDEA插件)。
- 业务建模:用类图描述业务实体关系(如电商系统中的
订单-商品)。
3. 类图的核心组成
| 元素 | 符号/规则 | 示例 | 补充说明 |
| 类名 | 首字母大写 | Animal | 抽象类名用斜体 |
| 接口 | <<interface>> + 接口名 | <<Flyable>> | 无属性,仅抽象方法 |
| 属性 | 可见性 名称: 类型 = 默认值 | -name: String = "Unknown" | 成员变量 |
| 操作(方法) | 可见性 名称(参数:类型): 返回类型 | +fly(speed: int): void | 代表类提供的服务 |
| 可见性 | + (public) - (private) # (protected) ~ (package) | #age: int | 控制访问权限- +表示公共属性或操作; |
- -表示私有属性或操作;
- #表示受保护的属性或操作;
- 〜表示包属性或操作。 |
4. 类关系
六种核心关系对比
| 关系类型 | 符号 | 方向 | 语义 | 代码体现 | 生命周期 |
| 继承 | ◁━ 实线 + 空心三角 | 子类 → 父类 | is-a(泛化) | class Duck extends Bird | 独立 |
| 实现 | ╌╌▷ 虚线 + 空心三角 | 实现类 → 接口 | 实现契约 | class Plane implements Flyable | 独立 |
| 关联 | ──> 实线箭头 | 持有类 → 被关联类 | 长期引用关系 | 成员变量 private Address address; | 独立 |
| 聚合 | ◇━━ 实线 + 空心菱形 | 部分类 ← 整体类 | has-a(弱拥有) | class Team { List<Member> members; } | 部分可独立存在 |
| 组合 | ◆━━ 实线 + 实心菱形 | 部分类 ← 整体类 | contains-a(强拥有) | class Car { Engine engine; } | 部分随整体销毁 |
| 依赖 | ╌╌> 虚线箭头 | 使用类 → 被依赖类 | 临时使用 | 局部变量/参数/返回值 | 临时 |
关键区别
- 聚合 vs 组合
-
- 聚合:部分可独立存在(如
教室和学生,学生可离开教室)。 - 组合:部分与整体共存亡(如
公司和部门,公司倒闭则部门消失)。
- 聚合:部分可独立存在(如
- 关联 vs 依赖
-
- 关联:长期持有对象引用(如
用户拥有地址)。 - 依赖:临时使用(如
订单调用支付工具的方法)。
- 关联:长期持有对象引用(如
4.1. 继承(或泛化)
- 表示一般与特殊的关系,是父类与子类之间的关系,是一种继承关系,是 is-a 的关系;
- 继承关系采用空心三角形+实线来表示, 由派生类指向基类。
4.2. 实现
- 是接口与实现类之间的关系。类实现了接口,类中的操作实现了接口中所声明的所有的抽象操作;
- 实现接口采用空心三角形+虚线来表示,由类指向接口。
4.3. 关联
- 是对象之间的一种引用关系,用于表示一类对象与另一类对象之间的联系;
- 两个对等类之间的结构链接;
- 关联关系采用实线箭头表示,箭头从使用类指向被关联的类。
4.4. 聚合
- 表示一种弱的“拥有”关系,是整体和部分之间的关系,是 has-a 的关系;
- 聚合关系是通过成员对象来实现的,其中成员对象是整体对象的一部分,但是成员对象可以脱离整体对象而独立存在;
- 聚合关系采用空心菱形+实线表示,菱形端为整体对象。
4.5. 复合(或组合)
- 表示一种强的“拥有”关系,体现了严格的部分和整体的关系,是contain-a的关系;
- 整体对象和部分对象的声明周期一样,一旦整体对象不存在,部分对象也将不存在,部分对象不能脱离整体对象而存在;
- 复合关系采用实心菱形+实线表示,菱形端为整体对象。
4.6. 依赖
这种关系通常表现为局部变量、方法返回值,方法的参数或者对某个方法的直接调用
- 表示一种使用关系,是临时性的关联;
- 依赖关系采用虚线箭头表示,箭头从使用类指向被依赖的类。
在 Java 类图中,依赖关系是一种比较常见的关系类型,表示一个类(或接口)使用了另一个类(或接口)的服务或功能,但并不持有对方的引用。下面列举了一些常见的依赖关系:
- 参数依赖
一个类的方法签名中包含另一个类的对象作为参数,表示这个类依赖于另一个类的实例。
public class ClassA {
public void method(ClassB b) {
// 使用 ClassB 的实例
}
}
- 局部变量依赖
一个类中的方法内部定义了另一个类的对象作为局部变量,表示这个类依赖于另一个类的实例。
public class ClassA {
public void method() {
ClassB b = new ClassB();
// 使用局部变量 b
}
}
- 返回值依赖
一个类的方法返回了另一个类的对象,表示这个类依赖于另一个类的实例。
public class ClassA {
public ClassB createObject() {
return new ClassB();
}
}
依赖关系是一种松耦合的关系,表示一个类对另一个类的使用,但并不是强关联,两者可以相互独立存在。
4.7. 类关系综合
5. 常见误区澄清
- 箭头方向混淆:继承箭头指向父类,依赖箭头指向被依赖类。
- 组合误用:当部分可独立存在时,应用聚合而非组合。
- 忽略可见性:
private属性不对外暴露,避免外部直接访问。