UML 类图
面向对象程序设计(Java)
掌握类图元素与关系,规范表达面向对象设计1.1 UML基础概念与类图定位
UML(Unified Modeling Language,统一建模语言)是一种标准化的图形建模语言,用于可视化、描述、构建和文档化软件系统的产物。
UML的定义与用途
- 定义:一种通用的、标准化的建模工具,不是编程语言
- 可视化:通过图形方式直观展示系统结构和行为
- 规范化:提供标准化的表达方式,减少沟通歧义
- 文档化:为系统设计提供完整、准确的文档记录
UML发展历史
- 1995年:Booch、Rumbaugh和Jacobson三位方法学家开始统一方法
- 1997年:UML 1.0被对象管理组织(OMG)采纳为标准
- 2005年:UML 2.0发布,引入更丰富的建模能力
- 2015年:UML 2.5发布,目前最新的稳定版本
类图在UML中的定位
类图是UML中的静态结构图,用于描述系统中类的静态结构以及它们之间的各种关系。与描述系统行为的动态图(如序列图、活动图)不同,类图关注的是系统的"快照",展示系统在某一时刻的结构组成。
最小可用类图示例
@startuml
class Student {
- id : int
+ name : String
+ getName() : String
+ setName(n : String) : void
}
@enduml
类图用于静态结构表达;属性与方法区分清晰,采用可见性标记描述访问约束。
2.1 类图核心要素:类、关系与接口
类图由三大核心要素构成:类(Class)、关系(Relationship)和接口(Interface)。这些要素共同描述了系统的静态结构。
1. 类(Class)的表示方法
类是类图的核心元素,由三部分组成:
- 名称栏:类的名称
- 属性栏:类的属性/字段
- 方法栏:类的操作/方法
2. 类之间的关系
类之间可以通过多种关系相互连接,每种关系有不同的语义:
- 关联(Association):类之间的结构关系
- 聚合(Aggregation):整体与部分的关系,部分可独立存在
- 组合(Composition):强聚合,部分不能独立存在
- 继承(Inheritance):一般与特殊的关系
- 实现(Realization):接口与实现类的关系
- 依赖(Dependency):一个类使用另一个类
3. 接口(Interface)的表示方式
接口是一种特殊的类,它定义了一组操作规范但没有实现,用于表达行为约定和抽象概念。
类是类图的核心元素,关系连接类形成结构,接口定义行为规范。
2.2 类成员可见性与抽象设计
深入理解类成员的可见性、抽象类与接口的使用。
类成员与可见性
可见性符号用于控制类成员的访问级别:
+:公有(public) - 所有类可访问-:私有(private) - 仅本类可访问#:受保护(protected) - 本类、子类及同包类可访问~:包级私有(package private) - 同包类可访问
类成员示例
@startuml
class Account {
- id : long
+ owner : String
# balance : BigDecimal
+ deposit(amount : BigDecimal) : void
+ withdraw(amount : BigDecimal) : boolean
}
@enduml
抽象类与接口
@startuml
interface AuthService {
+ login(u : String, p : String) : boolean
}
abstract class Person {
+ id : int
+ getId() : int
}
class Student extends Person {
+ name : String
}
Student ..|> AuthService
@enduml
接口用于行为约定;抽象类表达抽象通用性;实现关系以空心三角+虚线表示。
3.1 类元素语法:属性与方法
掌握类图元素的完整语法格式,能够更精确地表达设计意图。
属性的完整语法
可见性 名称 : 类型 [多重性] = 初始值 {属性特性}
- 可见性:+、-、#、~
- 多重性:[1]、[0..1]、[0..*]、[1..*]
- 属性特性:{readOnly}、{derived}、{static}
方法的完整语法
可见性 名称 (参数列表) : 返回类型 {方法特性}
- 参数列表:参数名 : 类型 [默认值]
- 方法特性:{query}、{static}、{abstract}
属性与方法示例
@startuml
class Product {
- id : long [1]
- name : String [1]
- price : double [1] = 0.0
- description : String [0..1]
+ {static} TAX_RATE : double = 0.08
+ {query} calculateTax() : double
+ {static} fromJson(json : String) : Product
+ {abstract} validate() : boolean
}
@enduml
属性和方法的完整语法提供了精确表达设计意图的能力,多重性和特性标记是关键要素。
4.1 强关系(结构性关系)
强关系表示类之间紧密的结构性依赖,修改一方会直接影响另一方。按照依赖强度从强到弱依次为:继承、实现、组合。
继承关系 - 最强
定义:表示"is-a"关系,子类完全依赖父类。
特点:修改父类会直接影响子类,子类继承父类的所有属性和方法。
表示方法:实线空心三角箭头,箭头指向父类。
实现关系 - 最强
定义:表示类完全依赖接口定义。
特点:必须实现所有接口方法,接口变更会影响实现类。
表示方法:虚线空心三角箭头,箭头指向接口。
组合关系 - 很强
定义:表示整体与部分的关系,部分不能独立于整体存在。
特点:生命周期强绑定,整体销毁时部分也随之销毁(如:汽车-引擎)。
表示方法:实心菱形端点的实线,菱形端点连接整体类。
@startuml
class Animal
class Dog extends Animal
interface Runnable
Dog ..|> Runnable
class Car
class Engine
Car *-- Engine
@enduml
强关系体现了类之间的结构性依赖,设计时需要谨慎考虑,因为修改会带来连锁影响。
4.2 弱关系(行为性关系)
弱关系表示类之间较为松散的连接,修改一方对另一方的影响较小。按照依赖强度从强到弱依次为:聚合、关联、依赖。
聚合关系 - 中等强度
定义:表示整体与部分的关系,部分可以独立于整体存在。
特点:"has-a"关系,生命周期独立(如:部门-员工)。
表示方法:空心菱形端点的实线,菱形端点连接整体类。
关联关系 - 较弱
定义:表示对象间的独立存在,只是相互引用。
特点:通常是长期关系,对象可以独立存在(如:学生-课程)。
表示方法:实线连接,可带箭头表示导航方向。
依赖关系 - 最弱
定义:表示临时性的使用关系。
特点:通常是方法参数、局部变量(如:方法调用时依赖某个类)。
表示方法:虚线箭头,箭头指向被依赖的类。
@startuml
class Department
class Employee
class Student
class Course
class OrderService
class EmailService
Department o-- "1..*" Employee
Student "0..*" -- "0..*" Course
OrderService ..> EmailService
@enduml
弱关系体现了类之间的行为性连接,设计时优先选择较弱的关系,以提高系统的灵活性和可维护性。
4.3 关联关系详解
关联关系是UML类图中最基本的关系类型,表示类之间的结构化连接。
关联关系(Association)
定义:表示类之间的结构化连接,描述对象之间的链接关系。
特点:是一种"has-a"关系,表示一个对象知道另一个对象的存在。
表示方法:实线连接,可带箭头表示导航方向,可标注多重性。
关联关系的类型
双向关联:两个类互相知道对方的存在,用无箭头的实线表示。
单向关联:只有一个类知道另一个类的存在,用带箭头的实线表示。
自关联:类与自身关联,表示类内部对象之间的关系。
多重性表示
1:恰好一个
0..1:零个或一个
* 或 0..*:零个或多个
1..*:一个或多个
n:固定数量
m..n:范围数量
@startuml
class Teacher
class Student
class Course
' 双向关联
Teacher "1" -- "0..*" Student : teaches >
' 单向关联
Teacher --> Course : teaches >
@enduml
关联关系是类图中最常用的关系,正确使用多重性可以精确表达类之间的数量约束。
4.4 聚合关系详解
聚合关系是关联关系的特殊形式,表示整体与部分的关系,但部分可以独立存在。
聚合关系(Aggregation)
定义:表示"has-a"关系的特殊形式,表示整体与部分的关系,但部分可以独立存在。
特点:部分对象的生命周期不依赖于整体对象,可以独立存在。
表示方法:空心菱形端点的实线,菱形端点连接整体类。
聚合关系的特征
生命周期独立:部分对象可以在整体对象创建之前存在,也可以在整体对象销毁后继续存在。
共享性:一个部分对象可以同时属于多个整体对象。
弱耦合:整体和部分之间的关系相对松散。
聚合关系的应用场景
部门与员工:部门包含员工,但员工可以独立存在,也可以属于多个部门。
汽车与轮胎:汽车有轮胎,但轮胎可以独立存在,也可以安装到其他汽车上。
团队与成员:团队由成员组成,但成员可以离开团队,也可以加入其他团队。
@startuml
class Department {
- name : String
}
class Employee {
- id : int
- name : String
}
' 聚合关系:部门包含员工,但员工可以独立存在
Department o-- Employee : contains >
@enduml
聚合关系强调了整体与部分的关系,但部分可以独立存在,这是与组合关系的主要区别。
4.5 组合关系详解
组合关系是聚合关系的特殊形式,表示更强的整体与部分关系,部分不能独立存在。
组合关系(Composition)
定义:表示更强的"has-a"关系,部分对象的生命周期依赖于整体对象。
特点:部分对象不能独立存在,整体对象销毁时,部分对象也随之销毁。
表示方法:实心菱形端点的实线,菱形端点连接整体类。
组合关系的特征
生命周期依赖:部分对象的生命周期完全依赖于整体对象。
独占性:一个部分对象在同一时间只能属于一个整体对象。
强耦合:整体和部分之间的关系非常紧密。
组合关系的应用场景
房子与房间:房子包含房间,房间不能独立存在,房子销毁时房间也随之销毁。
公司与部门:公司由部门组成,部门不能独立于公司存在。
文档与章节:文档由章节组成,章节不能独立于文档存在。
组合与聚合的区别
生命周期:组合中部分依赖整体,聚合中部分独立于整体。
共享性:组合中部分不能共享,聚合中部分可以共享。
表示方法:组合用实心菱形,聚合用空心菱形。
@startuml
class House {
- address : String
}
class Room {
- area : double
- type : String
}
class Door {
- material : String
}
' 组合关系:房子包含房间和门,房间和门不能独立存在
House *-- Room : contains >
House *-- Door : has >
@enduml
组合关系是最强的结构关系,表示部分的生命周期完全依赖于整体,体现了"部分不能脱离整体而存在"的语义。
4.6 依赖关系详解
依赖关系是UML类图中最弱的关系,表示一个类使用另一个类的临时性关系。
依赖关系(Dependency)
定义:表示一个类使用另一个类,通常是一种临时性的、较弱的关系。
特点:通常表现为一个类的方法使用另一个类作为参数、返回值或局部变量。
表示方法:虚线箭头,箭头指向被依赖的类。
依赖关系的表现形式
参数依赖:一个类的方法使用另一个类作为参数。
返回值依赖:一个类的方法返回另一个类的对象。
局部变量依赖:一个类的方法中定义了另一个类的局部变量。
静态方法调用:一个类调用另一个类的静态方法。
依赖关系的应用场景
服务调用:业务类调用服务类的方法。
工具类使用:业务类使用工具类进行辅助操作。
工厂模式:客户端类依赖工厂类创建对象。
依赖关系与其他关系的区别
临时性:依赖关系通常是临时的,而关联、聚合、组合是长期的结构关系。
弱耦合:依赖关系表示较弱的耦合,而其他关系表示较强的耦合。
使用方式:依赖关系表示"使用"关系,其他关系表示"拥有"关系。
@startuml
class OrderProcessor {
+ processOrder(order : Order) : void
}
class Order {
- items : List<OrderItem>
}
class EmailService {
+ sendEmail(to : String, content : String) : void
}
' 依赖关系:订单处理器依赖于订单和邮件服务
OrderProcessor ..> Order : uses >
OrderProcessor ..> EmailService : uses >
@enduml
依赖关系是最弱的关系,表示临时性的使用关系,合理使用依赖关系可以降低系统的耦合度。
4.7 继承关系详解
5. 继承关系(Inheritance/Generalization)
定义:表示"is-a"关系,子类继承父类的属性和方法。
特点:子类是父类的特化,具有父类的所有特性,并可以添加新的特性。
表示方法:实线空心三角箭头,箭头指向父类。
继承关系的核心特性
- 传递性:如果B继承A,C继承B,则C间接继承A
- 单根性:Java中类只能单继承,但可以多实现接口
- 访问控制:子类可以访问父类的protected和public成员
- 多态性:子类对象可以当作父类对象使用
@startuml
class Vehicle {
# speed : double
+ start() : void
+ stop() : void
}
class Car extends Vehicle {
- doors : int
+ openTrunk() : void
}
class Motorcycle extends Vehicle {
- type : String
+ doWheelie() : void
}
' 继承关系:汽车和摩托车继承自车辆
Car --|> Vehicle
Motorcycle --|> Vehicle
@enduml
继承是面向对象编程的核心机制,通过继承可以实现代码复用和建立清晰的类层次结构。设计时应遵循"里氏替换原则",确保子类可以替换父类而不影响程序正确性。
4.8 实现关系详解
实现关系(Realization/Implementation)
定义:表示类实现接口,接口定义了一组操作,类提供这些操作的具体实现。
特点:类必须实现接口中定义的所有方法,是一种契约关系。
表示方法:虚线空心三角箭头,箭头指向接口。
实现关系的核心特性
- 多实现性:一个类可以实现多个接口,弥补单继承的不足
- 契约性:接口定义了行为契约,实现类必须遵守
- 抽象性:接口只定义行为规范,不包含实现细节
- 多态性:通过接口引用可以调用不同实现类的方法
@startuml
interface Drawable {
+ draw() : void
+ resize(scale : double) : void
}
interface Movable {
+ move(dx : double, dy : double) : void
}
class Shape {
- x : double
- y : double
}
class Circle extends Shape implements Drawable, Movable {
- radius : double
+ draw() : void
+ resize(scale : double) : void
+ move(dx : double, dy : double) : void
}
' 实现关系:圆形实现了可绘制和可移动接口
Circle ..|> Drawable
Circle ..|> Movable
@enduml
继承与实现关系对比
| 对比项 | 继承关系 | 实现关系 |
|---|---|---|
| 语义 | is-a关系 | can-do关系 |
| 数量限制 | 单继承 | 多实现 |
| 内容 | 属性+方法 | 抽象方法 |
| 表示方法 | 实线空心三角 | 虚线空心三角 |
实现关系提供了灵活的多态机制,通过接口可以定义系统的行为规范,降低类之间的耦合度。设计时应优先使用接口而非具体类,遵循"面向接口编程"的原则。
3.2 关系语法与多重性表示
掌握类之间关系的语法表示,准确表达类之间的连接方式。
关系语法示例
@startuml
' 接口
interface Payable {
+getSalary(): double
}
' 抽象类
abstract class Person {
-name: String
-age: int
+getName(): String
}
' 具体类
class Employee {
-employeeId: String
+getSalary(): double
}
class Department {
-deptName: String
+addEmployee(emp: Employee): void
}
class Project {
-projectName: String
+startProject(): void
}
class Task {
-taskName: String
+complete(): void
}
' 工具类
class Calculator {
+calculateBonus(salary: double): double
}
' 继承关系
Employee --|> Person
' 实现关系
Employee ..|> Payable
' 关联关系
Employee "1" -- "*" Project : works on >
' 聚合关系
Department "1" o-- "*" Employee : contains >
' 组合关系
Project "1" *-- "1..*" Task : consists of >
' 依赖关系
Employee ..> Calculator : uses >
@enduml
掌握完整语法有助于精确表达设计意图,多重性和关系类型是关键要素。
5.1 类图绘制规范与最佳实践
保持命名统一、关系方向合理、标注多重性与可见性、适度分组。关注可读性与一致性。
规范示例
@startuml
package app {
class Controller
class Service
class Repository
}
Controller --> Service
Service --> Repository
class Utils {
{static} version : String
{static} now() : Date
}
@enduml
采用包分组、明确依赖方向、区分静态成员,保证图面简洁与表达准确。
5.2 实战案例:电商系统订单模块设计
通过一个完整的电商系统订单模块,展示类图在实际项目中的应用。
需求分析
- 客户可以下订单,一个订单包含多个订单项
- 每个订单项对应一个商品,包含数量和单价
- 订单需要支付,支持多种支付方式
- 系统需要记录订单状态和操作日志
类图设计
@startuml
package 电商系统 {
class Customer {
- id : long
- name : String
- email : String
+ register() : boolean
+ login(password : String) : boolean
+ placeOrder(items : List) : Order
}
class Order {
- orderNumber : String
- orderDate : Date
- totalAmount : BigDecimal
+ calculateTotal() : BigDecimal
+ addItem(item : OrderItem) : void
+ removeItem(item : OrderItem) : void
}
class OrderItem {
- quantity : int
- unitPrice : BigDecimal
+ getSubtotal() : BigDecimal
}
class Product {
- id : long
- name : String
- price : BigDecimal
- stock : int
+ updateStock(quantity : int) : void
+ isAvailable() : boolean
}
class PaymentResult {
- success : boolean
- transactionId : String
- message : String
}
interface PaymentService {
+ processPayment(amount : BigDecimal) : PaymentResult
}
class CreditCardPayment implements PaymentService {
+ processPayment(amount : BigDecimal) : PaymentResult
}
}
Customer "1" -- "0..*" Order : places >
Order "1" *-- "1..*" OrderItem : contains >
OrderItem "1" -- "1" Product : refers to >
Order ..|> PaymentService : uses >
@enduml
设计解析
- Customer与Order:一对多关联关系,一个客户可以有多个订单
- Order与OrderItem:组合关系,订单由多个订单项组成,订单项不能独立存在
- OrderItem与Product:关联关系,订单项引用一个商品
- Order与PaymentService:依赖关系,订单处理时需要使用支付服务
从需求分析到类图设计,识别核心类、定义属性方法、建立关系是关键步骤。
6.1 交互实践:PlantUML编辑器
在下方编辑区修改PlantUML代码,点击运行或直接输入实时预览;可选择导出为SVG或PNG。
6.2 类图与其他UML图的协作关系
类图是UML中的静态结构图,与其他UML图相互补充,共同构成完整的系统模型。
类图与序列图
- 类图:定义静态结构,展示类及其关系
- 序列图:展示对象间的动态交互过程
- 关系:类图中的类对应序列图中的对象,类图中的方法对应序列图中的消息
类图与用例图
- 用例图:描述系统功能需求,从用户视角展示系统功能
- 类图:实现用例所需的内部结构
- 关系:用例驱动类的设计,每个用例可能对应一组协作的类
类图与组件图
- 类图:展示系统内部微观结构
- 组件图:展示系统更高层次的组织结构
- 关系:组件由一组类组成,类图是组件图的细化
类图与活动图
- 活动图:描述业务流程或算法流程
- 类图:活动图中涉及的对象类型
- 关系:活动图中的操作通常对应类图中的方法
建模工具使用建议
- Enterprise Architect:功能全面,适合大型项目
- Visual Paradigm:界面友好,学习曲线平缓
- PlantUML:文本式建模,适合版本控制和协作
- StarUML:开源免费,适合中小型项目
类图设计最佳实践
- 保持简洁:避免在单个类图中展示过多信息
- 关注重点:根据受众调整展示的详细程度
- 遵循标准:使用标准UML符号和约定
- 合理分组:使用包或命名空间组织相关类
- 明确关系:准确表示类之间的关系和多重性
常见误区
- 过度设计:创建不必要的类和关系
- 细节过多:在类图中包含过多实现细节
- 关系混淆:错误使用关系类型(如混淆聚合和组合)
- 忽略约束:不标注重要的约束条件
- 不一致性:命名和表示方式不统一
类图是面向对象设计的重要工具,掌握它将帮助您更好地设计、沟通和实现软件系统。