UML类图

[toc]

1. UML概述

UML(Unified Modeling Language, 统一建模语言)是当前面向对象软件系统建模的标准语言 ,它融合了众多软件建模技术的优点 ,通过一系列标准的图形符号来描述系统 。 在设计模式的学习和使用过程中也需要掌握一些UML相关技术 , 尤其是UML类图 ,通过类图可以更好地理解每一个设计模式的结构并对每一个模式实例进行分析 。

2. 类与类的UML表示

2.1 类

类(Class)封装了数据和行为 ,是面向对象的重要组成部分,它是具有相同属性 、操作、关系的对象集合的总称。

类图(Class Diagram)使用出现在系统中的不同类来描述系统的静态结构 ,它用来描述 不同的类以及它们之间的关系 。

2.2 类的UML图示

在UML中类使用包含类名属性和操作且带有分隔线的长方形来表示:

对应的Java代码片段如下:

1
2
3
4
5
6
7
8
9
public class Employee {
private String name;
private int age;
private String email;

public void modifyInfo() {
...
}
}

在UML类图中, 类一般由三部分组成。

  1. 第一部分是列名;
  2. 第二部分是类的属性(Attributes):属性是指类的性质,即类的成员变量。一个类可以有任意多个属性,也可以没有属性。


    属性的标识方式如下:

    [ 可见性 ] 名称:类型 [ = 默认值 ]


  1. “可见性” 表示该属性对于类外的元素而言是否可见,它们的符号表示如下:

    公有(public) +
    私有(private) -
    受保护(protected) #
    默认 *
  2. ”名称“表示属性名,用一个字符串表示。
  3. “类型”表示属性的数据类型,可以是基本数据类型,也可以是用户自定义类型。
  4. “默认值是一个可选项,即属性的初始值。
    1. 第三部分是类的操作(Operations):操作是类的任意一个实例对象都可以使用的行为,是类的成员方法。

UML规定操作的表示方式如下:

[ 可见性 ] 名称([ 参数列表 ]) [ : 返回类型]


其中:

  1. “可见性”的定义和属性的可见性的定义相同。
  2. “名称”即方法名或操作名,用一个字符串表示。
  3. “参数列表”表示方法的参数,其语法与属性的定义相似 ,参数个数是任意的,多个参数之间用逗号” , “隔开 。
  4. “返回类型”是一个可选性,表示方法的返回值类型,依赖于具体的编程语言,可以是基本数据类型,也可以是用户自定义类型,还可以是空类型(void) ,如果是构造方法, 则无返回类型

2.3 类之间的关系

在软件系统中类并不是孤立存在的 ,类与类之间存在各种关系, 对于不同类型的关系, UML 提供了不同的表示方式。

2.3.1 关联关系

关联(Association)关系是类与类之间最常用的一种关系,它是一种结构化关系,用于表示一类对象与另一类对象之间有联系, 如汽车和轮胎 、 师傅和徒弟 、 班级和学生等。

在UML类图中用实线连接有关联关系的对象所对应的类,在使用 Java 、 C #和 C++等编程语言实现关联关系时,通常将一个类的对象作为另一个类的成员变量。

在使用类图表示关联关系时可以在关联线上标注角色名,一般使用一个表示两者之间关系的动词或者名词表示角色名(有时该名词为实例对象名) ,关系的两端代表两种不同的角色,因此在一个关联关系中可以包含两个角色名,角色名不是必须的 ,可以根据需要增加 , 其目的是使类之间的关系更加明确 。

对应的Java代码如下:

1
2
3
4
5
6
7
8
public class LoginForm {
private JButton loginButton; //定义为成员变量
...
}

public class JButton {
...
}

在UML中,关联关系包含以下集中形式:

  1. 双向关联

    在默认情况下关联是双向的。例如顾客(Customer)购买商品(Product)并拥有商品,反之,卖出的商品总有某个顾客与之相关联。 因此,Customer 类和 Product 类之间具有双向关联关系, 如下图:

    对应的Java片段如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Customer {
    private Productor[] products;
    ...
    }

    public class Product {
    private Customer customer;
    ...
    }
  2. 单向关联

    类的关联关系也可以是单向的,单向关联用带箭头的实线表示。例如顾客(Customer)拥有地址 (Address), 则Customer类与Address类具有单向关联关系,如下图:

    1
    2
    3
    4
    5
    classDiagram
    Customer --> Address : has
    class Customer {
    - address : Address
    }

    对应的Java片段如下:

    1
    2
    3
    4
    5
    6
    7
    8
    public class Customer {
    private Address address;
    ...
    }

    public class Address {
    ...
    }
  3. 自关联

    在系统中可能会存在一些类的属性对象类型为该类本身 , 这种特殊的关联关系称为自关联。 例如一个结点类(Node)的成员又是结点 Node 类型的对象 ,如下图:

    对应的Java代码如下:

    1
    2
    3
    4
    public class Node {
    private Node subNode;
    ...
    }
  4. 多重性关联

    多重性关联关系又称为重数性(Multiplicity)关联关系,表示两个关联对象在数量上的对应关系。 在UML中对象之间的多重性可以直接在关联直线上用一个数字或一个数字范围表示。

    常见的多重性表示方式如下表所示:

    多重性表示方式表
    表示方式 多重性说明
    1. .1 表示另—个类的一个对象只与该类的一个对象有关系
    0. .* 表示另—个类的一个对象与该类的零个或多个对象有关系
    1. .* 表示另—个类的一个对象只与该类的一个对象或多个对象有关系
    0. .1 表示另—个类的一个对象没有或只与该类的一个对象有关系
    m. .n 表示另—个类的一个对象与该类最少m最多n个对象有关系(m <= n)

    例如一个界面(Form)可以拥有零个或多个按钮(Button) ,但是一个按钮只能属于一个界面, 因此一个Form类的对象可以与零个或多个Button类的对象相关联, 但一个Button类的对象只能与一个Form类的对象关联 ,如图所示:

    对应的Java代码片段如下:

    1
    2
    3
    4
    5
    6
    7
    8
    public class Form {
    private Button[] button; //定义一个集合对象
    ...
    }

    public class Button {
    ...
    }
  5. 聚合关系

    聚合(Aggregation)关系表示整体与部分的关系 。 在聚合关系中 ,成员对象是整体对象的一部分 ,但是成员对象可以脱离整体对象独立存在。 在UML中 ,聚合关系用带空心菱形的直线表示 。 例如汽车发动机(Engine)是汽车(Car)的组成部分 ,但是汽车发动机可以独立存在 , 因此汽车和发动机是聚合关系,如图所示:

    对应的Java代码片段如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class Car {
    private Engine engine;
    //构造注入
    public Car( Engine engine){
    this.engine = engine;
    )
    //设值注入
    public void setEngine(Engine engine){
    this.engine = engine;
    )
    )

    public class Engine {
    }
  6. 组合关系

    组合(Composition)关系也表示类之间整体和部分的关系,但是在组合关系中整体对象可以控制成员对象的生命周期,一旦整体对象不存在,成员对象也将不存在,成员对象与整体对象之间具有同生共死的关系。 在UML中,组合关系用带实心菱形的直线表示 。 例如人的头(Head)与嘴巴(Mouth) , 嘴巴是头的组成部分之一, 而且如果头没了, 嘴巴也就没了,因此头和嘴巴是组合关系,如图所示:

    Java代码片段如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Head {
    private Mouth mouth;

    public Head() {
    mouth = new Mouth();//实例化成员类
    }
    ...
    }

    public class Mouth {
    ...
    }

2.3.2 依赖关系

依赖(Dependency )关系是一种使用关系 ,特定事物的改变有可能会影响到使用该事物的其他事物, 在需要表示一个事物使用另一个事物时使用依赖关系。 在大多数情况下, 依赖关系体现在某个类的方法使用另一个类的对象作为参数。 在UML中, 依赖关系用带箭头的虚线表示, 由依赖 的一方指向被依赖 的一方 。

对应的Java代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Driver {
public void drive(Car car) {
car.move();
}
...
}

public class Car {
public void move() {
...
}
...
}

在系统实现阶段, 依赖关系通常通过3种方式来实现:

第一种(也是最常用的一种方式) 将一个类的对象作为另一个类中方法的参数(如上例);

第二种方式是在一个类的方法中将另一个类的对象作为其局部变量;

第三种方式是在一个类的方法中调用另一个类的静态方法。

2.3.3 泛化关系

泛化(Generalization)关系也就是继承关系 ,用于描述父类与子类之间的关系 , 父类又称作基类或超类, 子类又称作派生类。 在UML中, 泛化关系用带空心三角形的直线来表示 。

对应的Java片段如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 父类
public class Person {
protected String name;
protected int age;
public void move() {
...
}
public void say() {
...
}
}

// 子类
public class Student extends Person {
private String studentNo;
public void study() {
...
}
}

// 子类
public class Teacher extends Person {
private String teacherNo;
public void teach() {
...
}
}

2.3.4 接口与实现关系

在 UML 中用与类的表示法类似的方式表示接口,接口之间也可以有与类之间关系类似的继承关系和依赖关系,但是接口和类之间还存在一种实现(Realization)关系,在这种关系中类实现了接口,类中的操作实现了接口中所声明的操作。在UML中,类与接口之间的实现关系用带空心三角形的虚线来表示。

对应的Java代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface Vehicle {
public void move();
}

public class Ship implements Vehicle {
public void move() {
...
}
}

public class Car implements Vehicle {
public void move() {
...
}
}