依赖关系
依赖关系(Dependency)是一种使用关系,特定事物的改变有可能会影响到使用该事物的其他事物,在需要表示一个事物使用另一个事物时使用依赖关系。通常,依赖关系体现在某个类的方法使用另一个类的对象作为参数。
在UML中,依赖关系用带箭头的虚线表示,由依赖的一方指向被依赖的一方。
比如:驾驶员开车,Driver类的driver()方法中将Car类的对象car作为参数传递,以便在driver()方法中调用car的move()方法,且驾驶员的driver()方法依赖car的move()方法,因此Driver类依赖于Car类。
1 public class Driver 2 { 3 public void drive(Car car) 4 { 5 car.move(); 6 } 7 } 8 9 public class Car 10 { 11 public void move() 12 { 13 ... 14 } 15 }
如果在一个类的方法中调用了另一个类的静态方法,或者在一个类的方法中定义了另一个类的对象作为其局部变量,也是依赖关系的一种表现形式。
关联关系
关联关系有以下几种:双向关联,单项关联,自关联,多重性关联,聚合关系,组合关系。
关联关系(Association)是类与类之间最常用的一种关系,它是一种结构化关系,用于表示一类对象与另一类对象之间有联系。通常将一个类的对象作为另一个类的属性。
在UML类图中,用实线连接有关联的对象所对应的类,可以在关联线上标注角色名。
比如:一个登录界面的LoginForm中包含一个JButton类的注册按钮loginButton它们之间可以表示为关联关系。
1 public class LoginForm 2 { 3 private JButton loginButton; 4 ... 5 } 6 7 public class JButton 8 { 9 ... 10 }
双向关联
默认情况下,关联是双向的,双向关联用直线表示。
比如:顾客(Customer)购买商品(Product)并拥有商品,反之,卖出的商品总是有对应的顾客与之对应。
1 public class Customer 2 { 3 private Product[] products; 4 ... 5 } 6 7 public class Product 8 { 9 private Customer customer; 10 ... 11 }
单向关联
类的关联关系也可以是单向的,单向关联用带箭头的实线表示。
比如:顾客(Customer)拥有地址(Address),则顾客和地址拥有单向关联关系。
1 public class Customer 2 { 3 private Address address; 4 ... 5 } 6 7 public class Address 8 { 9 ... 10 }
自关联
在系统中可能会存在一些类的属性对象类型为该类本身,这种特殊的关联关系称为自关联。
比如:节点类(Node)的成员又是节点对象。
1 public class Node 2 { 3 private Node subNode; 4 ... 5 }
多重关联
重数性关联关系又称为多重性关联关系(Multiplicity),表示一个类的对象与另一个类的对象连接的个数。在UML中多重性关系可以直接在关联直线上增加一个数字表示与之对应的另一个类的对象的个数。
表示方式 |
多重性说明 |
1..1 |
表示另一个类的一个对象只与一个该类对象有关系 |
0..* |
表示另一个类的一个对象与零个或多个该类对象有关系 |
1..* |
表示另一个类的一个对象与一个或多个该类对象有关系 |
0..1 |
表示另一个类的一个对象没有或只与一个该类对象有关系 |
m..n |
表示另一个类的一个对象与最少m、最多n个该类对象有关系(m<=n) |
比如:一个界面(Form)可以拥有零个或者多个按钮(Buttom),但是一个按钮只能属于一个界面。
1 public class Form 2 { 3 private Button buttons[]; 4 ... 5 } 6 7 public class Button 8 { 9 ... 10 }
聚合
聚合关系(Aggregation)表示一个整体与部分的关系。通常在定义一个整体类后,再去分析这个整体类的组成结构,从而找出一些成员类,该整体类和成员类之间就形成了聚合关系。
在聚合关系中,成员类是整体类的一部分,即成员对象是整体对象的一部分,但是成员对象可以脱离整体对象独立存在。通常不直接实例化成员对象,通过构造函数或者Setter方法注入。
在UML中,聚合关系用带空心菱形的直线表示。
比如:发动机是汽车的组成部分,但是发动机可以独立于汽车存在,则汽车和发动机是聚合关系。
1 public class Car 2 { 3 private Engine engine; 4 public Car(Engine engine) 5 { 6 this.engine = engine; 7 } 8 9 public void setEngine(Engine engine) 10 { 11 this.engine = engine; 12 } 13 ... 14 } 15 16 public class Engine 17 { 18 ... 19 }
Car中定义了Engine类型的成员对象,Engine是Car的一部分,但是Engine可以脱离Car单独存在,因为在Car类中并没有直接实例化Engine,而是通过构造函数或者Setter方法将类外部实例化好的对象以参数形式传入Car中,这种方式成为注入。因为Engine和Car的实例化时刻不相同,因此它们之间不存在生命周期的制约关系仅仅只是部分与整体之间的关系。聚合关系表示整体与部分的关系较弱。
组合
组合关系(Composition)也表示类之间整体和部分的关系,但是组合关系中部分和整体具有统一的生存期。一旦整体对象不存在,部分对象也将不存在,部分对象与整体对象之间具有同生共死的关系。通常定义了成员对象后通过构造函数实例化。
在组合关系中,成员类是整体类的一部分,而且整体类可以控制成员类的生命周期,即成员类的存在依赖于整体类。
在UML中,组合关系用带实心菱形的直线表示。
比如:人的头和嘴巴,嘴把是头的组成部分。
1 public class Head 2 { 3 private Mouth mouth; 4 public Head() 5 { 6 mouth = new Mouth(); 7 } 8 ... 9 } 10 11 public class Mouth 12 { 13 ... 14 }
因为Head的构造函数中实例化了Mouth对象,因此在创建Head对象同时将创建Mouth对象,销毁Head对象同时销毁Mouth对象。整体控制局部的生命周期。组合关系表示整体与部分的关系较弱。
- 聚合与组合的共同点就是一个类的实例时另外一个类的成员对象。
- 聚合与组合和普通关联关系主要是语义上的区别。比如:客户与产品的关系就不能用聚合和组合,产品并不是客户的一部分,不存在整体与部分的关系,只能用普通的关联。
泛化关系
泛化关系(Generalization)也就是继承关系,也称为“is-a-kind-of”关系,泛化关系用于描述父类与子类之间的关系,父类又称作基类或超类,子类又称作派生类。在UML中,泛化关系用带空心三角形的直线来表示。
在代码实现时,使用面向对象的继承机制来实现泛化关系,如在Java语言中使用extends关键字、在C++/C#中使用冒号“:”来实现。
比如:Student类和Teacher类都继承了Person类的属性和方法,Student类中增加了属性学号studentNo和方法study(),Teacher类中增加了属性编号teacherNo和方法teach()。
1 public class Person 2 { 3 protected String name; 4 protected int age; 5 public void move() 6 { 7 ... 8 } 9 public void say() 10 { 11 ... 12 } 13 } 14 15 public class Student extends Person 16 { 17 private String studentNo; 18 public void study() 19 { 20 ... 21 } 22 }
接口实现关系
接口之间也可以有与类之间关系类似的继承关系和依赖关系,但是接口和类之间还存在一种实现关系(Realization),在这种关系中,类实现了接口,类中的操作实现了接口中所声明的操作。在UML中,类与接口之间的实现关系用带空心三角形的虚线来表示。
比如:定义了交通工具类Vehicle,有一个抽象操作move(),类Ship和Car都实现了这些操作,但实现细节不一样。
1 public interface Vehicle 2 { 3 public void move(); 4 } 5 6 public class Ship implements Vehicle 7 { 8 public void move() 9 { 10 ... 11 } 12 } 13 14 public class Car implements Vehicle 15 { 16 public void move() 17 { 18 ... 19 } 20 }