一、UML 类图元素
1.1 类的表示
在UML中,类表示为一个矩形框,分为三个区域。
- 第一区域是类名。
- 第二区域列出属性。
- 第三区域列出方法。
1.2 关系的表示
UML类图中有多种类型的关系:
- 关联(Association)
- 聚合(Aggregation)
- 组合(Composition)
- 继承(Inheritance)或泛化(Generalization)
- 依赖(Dependency)
- 实现(Realization)
二、符号与访问权限
- 公共成员:用
+
表示 - 私有成员:用
-
表示 - 受保护成员:用
#
表示
三、从代码到类图
3.1 绘制简单的类
我们以一个示例代码为模型,这个模型涉及到学生、课程、教师、和一个图书馆。:
#include <string>
#include <vector>
// 基类(父类)Person
class Person {
public:
Person(std::string name): name(name) {}
virtual void showName() { /*...*/ } // 虚函数
private:
std::string name;
};
// 子类 Student
class Student : public Person {
public:
Student(std::string name, int studentID): Person(name), studentID(studentID) {}
void enrollCourse(class Course*); // 单项关联
virtual void showName() override { /*...*/ } // 覆写虚函数
private:
int studentID;
std::vector<class Course*> courses; // 自关联
};
// 子类 Teacher
class Teacher : public Person {
public:
Teacher(std::string name, int teacherID): Person(name), teacherID(teacherID) {}
void assignCourse(class Course*);
private:
int teacherID;
};
// Course 类
class Course {
public:
Course(std::string name): name(name) {}
void setTeacher(Teacher*); // 单项关联
private:
std::string name;
Teacher* teacher; // 双向关联
std::vector<Student*> students; // 双向关联
};
// Library 类
class Library {
public:
Library(std::vector<class Book*> books): books(books) {}
private:
std::vector<class Book*> books; // 聚合关系
};
// Book 类
class Book {
public:
Book(std::string title): title(title) {}
};
// School 类
class School {
public:
School(std::vector<Student*> students, Library* library): students(students), library(library) {}
private:
std::vector<Student*> students; // 组合关系
Library* library; // 组合关系
};
3.2 继承关系
如果一个类继承自另一个类,那么在UML中,两者之间用一条带有空心箭头的直线连接。箭头从子类指向父类。
- UML 符号:一个空心三角形箭头从子类指向基类。
- 意义:子类继承基类的所有属性和方法。在代码中,这通常通过
extends
(Java)、:
(C++)等关键字实现。 - 例子:在一个学校模型里,
Teacher
和Student
都是Person
类的子类,继承了Person
的属性和方法。
3.3 关联关系
一个类作为另外一个类的子类即为关联关系
3.3.1 单项关联
- UML 符号:一个箭头从一个类指向另一个类。
- 意义:一个类知道另一个类的信息,并与之交互,但反过来则不然。
- 例子:在一个订单系统里,
Order
类有一个指向Customer
类的指针或引用,表示这个订单属于哪个客户,但Customer
类不需要知道具体的Order
。
3.3.2 双向关联
- UML 符号:一条直线连接两个类,没有箭头或两端都有箭头。
- 意义:两个类都知道对方,并可能互相交互。
- 例子:在一个社交网络模型里,一个
User
类可能有一个朋友列表,其中包括其他User
实例的引用。反之亦然,那些User
实例也有一个包含原User
实例的朋友列表。
3.3.3 自关联
- UML 符号:一条箭头从一个类指回到同一个类。
- 意义:类的实例与同类的其他实例有某种关系。
- 例子1:在一个组织图模型里,一个
Employee
类可以有一个“经理”字段,该字段是Employee
类的另一个实例。 - 例子2:链表关系,指向自己类型
3.4 聚合与组合关系
3.4.1 聚合
- UML 符号:一个空心菱形箭头从“整体”指向“部分”。
- 意义:一个类是另一个类的一部分,但两者具有各自的生命周期。
- 例子:在一个学校模型里,
School
类可能有多个Classroom
实例,但Classroom
也可以单独存在。
3.4.2 组合
- UML 符号:一个实心菱形箭头从“整体”指向“部分”。
- 意义:一个类是另一个类的一部分,并且两者有相同的生命周期。
- 例子:在一个机体模型里,
Car
类有多个Wheel
实例。当Car
实例被销毁时,其Wheel
实例也会被销毁。
3.5 依赖关系
在本示例代码中没有显示,但通常如果一个类使用了另一个类的方法或属性,那么这通常表示为依赖关系。在UML中,依赖关系表示一个类依赖于另一个类的定义。这通常是一个相对较弱的关系,并且通常表示为一个带箭头的虚线。
在代码中,依赖关系可能表现为以下几种形式:
在UML类图中, ReportGenerator
类画出两条带箭头的虚线,分别指向 Database
和 Report
,表示依赖关系。
- 一个类的方法使用了另一个类的对象。
- 一个类的方法接受另一个类的对象作为参数。
- 一个类的方法创建并返回另一个类的对象。
-
class Database { public: // ... 省略 }; class Report { public: // ... 省略 }; class ReportGenerator { public: ReportGenerator(Database& db): db(db) {} Report generate() { // 使用了 Database,因此依赖于 Database // 创建了一个 Report 对象,因此依赖于 Report Report report; // ... 省略代码 return report; } private: Database& db; };
在这个例子中:
ReportGenerator
依赖于Database
,因为它的generate
方法需要访问Database
。ReportGenerator
依赖于Report
,因为它的generate
方法创建并返回了一个Report
对象。
3.6 虚函数
在UML类图中,抽象类的名称通常会用斜体表示。如果一个C++类中包含至少一个纯虚函数(pure virtual function),那么这个类就是抽象的。
四、绘制类图