欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > UML:类图

UML:类图

2025/6/23 13:58:23 来源:https://blog.csdn.net/m0_74182461/article/details/148827186  浏览:    关键词:UML:类图

类图(Class Diagram)是统一建模语言(UML)中最核心、最常用的一种图,它用于静态地描述系统中的类、接口以及它们之间的关系。简单来说,类图就是你系统“骨架”的蓝图。


一、什么是UML类图?

简单来说,UML类图是一种静态的结构图,它用于描述系统中存在的类、接口以及它们之间相互关系的可视化表示。它不关注系统运行时的行为,而是聚焦于系统“骨架”的组成和连接方式。

类图就像是一张程序的“DNA”图谱,它告诉你:

  • 系统有哪些核心组件(类和接口)。
  • 每个组件有什么数据(属性)和功能(操作)。
  • 这些组件之间是如何联系、协作的。

二、类图的构成要素

类图主要由以下核心元素组成:

1. 类 (Class)

类是面向对象编程中最基本的构建块,它封装了数据(属性)和行为(操作)。在UML类图中,一个类通常表示为一个三层的矩形:

  • 顶层:类名 (Class Name)。
  • 中层:属性 (Attributes),描述类的数据特征。通常表示为 :

      可见性 属性名: 类型 [= 默认值]
     
  • 底层:操作 (Operations / Methods),描述类的行为。通常表示为:

     可见性 操作名(参数列表): 返回类型

在定义属性和操作时,我们需要明确它们的可见性(Visibility),这决定了它们能被哪些部分访问:

  • + (Public):公共的,任何地方都可以访问。
  • - (Private):私有的,只能在类内部访问。
  • # (Protected):受保护的,可以在类内部及子类中访问。
  • ~ (Package/Default):包(或默认)访问,同一包内的类可以访问。

此外,还有一些特殊的表示法:

  • =:表示属性有默认值
  • __ (下划线):表示属性或操作是静态 (static) 的。

为了更直观地理解这些概念,让我们来看一段 Java 代码,它定义了一个 Student 类,并包含了不同可见性、默认值以及静态成员的属性和操作:

public class Student {private String studentId;public String name = "Saul";protected int age;String department; // 在 Java 中,不加修饰符即为包内可见private static String SCHOOL_NAME;public String getStudentId() {return studentId;}private void calculateGPA() {System.out.println("Calculating GPA for " + name + "...");}protected void enrollCourse(String courseName) {System.out.println(name + " is enrolling in " + courseName + ".");}void updateInfo(String newDepartment) {this.department = newDepartment;System.out.println(name + "'s department updated to " + newDepartment + ".");}
}

这段 Student 类的代码在UML类图中的表示如下:

                            

抽象类是一种特殊的类,它不能被直接实例化,只能作为其他类的父类被继承。 抽象类可以包含抽象方法(只有方法签名没有具体实现)和具体方法。抽象方法必须由其非抽象子类实现。

在UML类图中,抽象类名和抽象方法名通常用斜体表示(也可以用两个尖括号包裹来表示抽象)。

                                                              

2. 接口 (Interface)

接口定义了一组操作的契约或规范,但不包含具体的实现。 它们用于定义行为规范,实现类必须遵循这些规范。

例如,我们定义一个 Flyable 接口,它规定了任何“可飞”的实体都必须具备的行为:

public interface Flyable {// 接口中所有方法默认都是 public abstract,无需显式写出void fly();
}

这段代码在UML类图中可以有两种常见的表示方法:

  1. 矩形表示法: 与类类似,但在类名前添加 <<interface>> 关键字,并列出其方法。
  2. 棒棒糖表示法(或接口符号表示法): 一个小圆圈和一条实线,简洁地表示接口,圆圈旁边标注接口名,线连接到实现类。

下方这张图清晰地展示了这两种表示方法,并描绘了一个类如何实现一个接口:

3. 关系 (Relationships)

类与类之间不是孤立的,它们通过各种关系连接起来,共同完成系统功能。理解这些关系是绘制类图的关键。

3.1 关联 (Association)

关联是最通用、最弱的一种关系,表示两个类之间的结构化连接,它们彼此独立存在,但有业务上的联系。

  • 多重性 (Multiplicity): 表示一个类的实例与另一个类的实例关联的数量(如 10..1*1..*m..n)。
  • 导航性 (Navigability): 表示关联的方向,默认双向,可加箭头表示单向。
  • 角色名 (Role Name): 描述一个类在关联中扮演的角色。

文字描述: 一个“订单”属于一个“客户”,而一个“客户”可以有多个“订单”。

代码体现: 一个类作为另一个类的成员变量。多重性通过集合类型(如 ListSet)体现。

// Java 关键代码片段
class Customer {private String customerId;private List<Order> orders; // Customer 关联多个 Order// ...
}class Order {private String orderId;private Customer customer; // Order 关联一个 Customer // ...
}

对应UML图: 

                        

3.2 聚合 (Aggregation)

聚合是 整体-部分” 关系的一种,表示部分可以独立于整体存在。整体与部分之间是“包含”关系,但部分的生命周期不依赖于整体。

符号描述聚合关系用 带空心菱形的直线 表示,空心菱形位于“整体”一端,指向“部分”。

文字描述: 一个“部门”包含多个“员工”,但即使部门解散,员工仍然可以存在或加入其他部门。

代码体现: 整体类通过注入(构造函数参数或setter方法)获取部分对象的引用,而不负责部分的创建。

// Java 关键代码片段
class Department {private String name;private List<Employee> employees; // Department 聚合 Employee 集合public Department(String name, List<Employee> employees) { // 注入 employeesthis.name = name;this.employees = employees;}// ...
}class Employee {private String employeeId;// ...
}

对应UML图:  

                                          

3.3 组合 (Composition)

组合是比聚合更强的一种“整体-部分”关系,表示部分与整体的生命周期强绑定。如果整体被销毁,部分也随之销毁。

符号描述组合关系用带 实心菱形的直线 表示,实心菱形位于“整体”一端,指向“部分”。

文字描述: 一栋“房子”包含多个“房间”,如果房子被拆除,房间也就不复存在了。

代码体现: 整体类在自身内部负责创建部分对象,且部分对象的生命周期完全由整体控制。

// Java 关键代码片段
class House {private String address;private List<Room> rooms; // House 组合 Room 集合public House(String address, int numberOfRooms) {this.address = address;this.rooms = new ArrayList<>();for (int i = 0; i < numberOfRooms; i++) {this.rooms.add(new Room("Room " + (i + 1))); // House 负责创建 Room}}// ...
}class Room {private String name;// ...
}

对应UML图: 

                                               

3.4 依赖 (Dependency)

依赖是一种弱关系,表示一个类临时性地使用另一个类。当一个类的改动可能影响另一个类时,就存在依赖关系。它通常是方法层面的关系,而非成员变量层面的长期持有。

符号描述:依赖关系 带箭头的虚线 表示,由 依赖 的一方 指向 被依赖的一方

文字描述: “司机”驾驶“汽车”,司机的行为在特定时刻需要汽车,但司机和汽车可以独立存在。

代码体现: 一个类的方法局部使用另一个类的对象(作为方法参数、局部变量或返回类型)

// Java 关键代码片段
class Driver {private String name;public void drive(Car car) { // Car 作为方法参数System.out.println(name + " 正在驾驶 " + car.getModel());car.start();// ...}// ...
}class Car {private String model;public void start() { /* ... */ }// ...
}

对应UML图:  

                                                  

3.5 泛化 (Generalization / Inheritance)

泛化表示继承关系,即一个类(子类)继承另一个类(父类)的属性和操作。这是一种典型的
“is-a”关系。

 符号描述:泛化关系 带空心三角形的实线 来表示,空心三角形指向父类(或超类),从子类(或派生类)发出。

文字描述: “狗”是一种“动物”,它拥有动物的普遍特征,同时也有自己特有的行为。

代码体现: 子类使用 extends 关键字继承父类。

// Java 关键代码片段
class Animal {private String name;public void eat() { /* ... */ }// ...
}class Dog extends Animal { // Dog 继承 Animalprivate String breed;public void bark() { /* ... */ }// ...
}

对应UML图:   

                                              

3.6 实现 (Realization / Implementation)

实现表示一个类实现了接口中定义的操作。类遵循接口定义的契约。

符号描述:实现关系用带空心三角形的虚线来表示。空心三角形指向接口,从实现类发出。

文字描述: “汽车”实现了“交通工具”接口中定义的行为,例如启动引擎、加速。

代码体现: 类使用 implements 关键字来实现一个或多个接口。

// Java 关键代码片段
interface Vehicle {void startEngine();void accelerate();
}class Car implements Vehicle { // Car 实现 Vehicle 接口private String model;@Overridepublic void startEngine() { /* ... */ }@Overridepublic void accelerate() { /* ... */ }// ...
}

对应UML图:    

                                                    


三、UML类图例题与绘制

理论知识的学习最终要落实到实践中。本节将通过一个具体的例题,带你一步步分析需求,识别类与关系,最终绘制出完整的UML类图。

例题:图形工厂的设计

题目描述:

图形(Shape)可分为圆形(Circle)、矩形(Rectangle)、椭圆形(Ellipse)等具体图形,在Shape类中提供了一个抽象的draw()方法用于绘制图形,而在具体的图形类中实现该抽象draw()方法。

提供一个图形工厂类(ShapeFactory),该类提供一个静态方法createShape(char type),其返回类型为Shape,参数type为所需绘制图形对应的代码,例如“c”表示圆形,“r”表示矩形,“e”表示椭圆形等,在createShape()方法中,可以使用条件语句来判断所需绘制图形的类型,并根据参数的不同返回不同的具体形状对象。

【注:“创建关系”是一种特殊的“依赖关系”】

题目分析与步骤解答:

我们将分步进行分析和绘制。

步骤 1:识别核心实体和它们之间的泛化关系

分析:

题目明确指出“图形(Shape)可分为圆形(Circle)、矩形(Rectangle)、椭圆形(Ellipse)等具体图形”,这天然地构成了泛化(继承)关系。Shape 是父类,Circle、Rectangle、Ellipse 是子类。

另外,“Shape类中提供了一个抽象的draw()方法”,说明 Shape 是一个抽象类,其 draw() 方法是抽象方法。而具体图形类则需要实现这个抽象方法。

识别的类: Shape, Circle, Rectangle, Ellipse

识别的关系: Circle 泛化自 Shape,Rectangle 泛化自 Shape,Ellipse 泛化自 Shape。

类的属性和操作(初步):

  • Shape: 抽象方法 + draw(): void。类名和方法名用斜体表示。
  • Circle: 实现 + draw(): void,可能还有半径等特有属性。
  • Rectangle: 实现 + draw(): void,可能还有长宽等特有属性。
  • Ellipse: 实现 + draw(): void,可能还有长短轴等特有属性。

            

步骤 2:引入图形工厂类并识别依赖关系

分析:

题目要求提供一个“图形工厂类(ShapeFactory)”,该类提供一个“静态方法createShape(char type)”,返回类型为 Shape。这个方法根据传入的 type 参数(如“c”、“r”、“e”)来创建并返回不同的具体形状对象(Circle, Rectangle, Ellipse)。

关键点在于题目注释:“创建关系”是一种特殊的“依赖关系”。这意味着 ShapeFactory 的 createShape 方法会临时使用或创建 Circle、Rectangle、Ellipse 的实例,但 ShapeFactory 不会持有这些形状作为其成员变量。同时,ShapeFactory 会返回一个 Shape 类型的对象,这也体现了对 Shape 的依赖。

识别的类: ShapeFactory

识别的关系:

  • ShapeFactory 依赖于 Shape (作为返回类型)。
  • ShapeFactory 依赖于 Circle, Rectangle, Ellipse (在方法内部创建它们的实例)。

类的属性和操作(补充):

  • ShapeFactory: 静态方法 + {static} createShape(type: char): Shape

                     

总结与思考:

通过这个例子,我们综合运用了以下UML类图知识点:

  • 抽象类与抽象方法: Shape 及其 draw() 方法的表示。
  • 泛化(继承): 子类如何继承抽象父类。
  • 依赖关系: ShapeFactory 如何在方法内部临时使用并创建其他类的实例。
  • 静态成员: ShapeFactorycreateShape 静态方法的表示。

 四、总结

        UML类图是软件工程中的一项基本功,它不仅仅是绘图,更是系统设计和思考过程的可视化。通过绘制和理解类图,我们能够更好地分析问题、设计解决方案、进行团队沟通并最终交付高质量的软件。

        回顾这篇博客,我们从类图的基本概念出发,详细探讨了它的构成要素(类、抽象类、接口及其各自的符号表示),以及类与类之间多样的关系(关联、聚合、组合、依赖、泛化、实现)。每一个关系我们都结合了代码示例和直观的UML图,力求让你能够清晰地理解这些抽象概念在实际编程中的映射。

        最后,通过“图形工厂”的例题,我们实践了如何将实际需求转化为UML类图,巩固了抽象类、泛化、以及工厂模式中创建关系的依赖等核心知识点。这展示了类图不仅是静态结构的描述工具,更是指导我们进行面向对象设计、提高代码可维护性和扩展性的有力武器。

掌握类图,意味着你能够:

  • 清晰地表达设计意图,让团队成员和利益相关者对系统结构一目了然。
  • 更好地理解现有系统,快速定位核心模块和关键交互。
  • 指导高质量的代码实现,确保设计与代码的一致性。
  • 提升设计思维,在复杂问题面前能够系统性地进行分解和抽象。

从现在开始,尝试在你的项目中多运用类图吧!从简单的概念到复杂的系统,它都能帮你理清思路,让你的设计更上一层楼。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词