这里不会将 UML 的各种元素都提到,我只想讲讲类图中各个类之间的关系;能看懂类图中各个类之间的线条、箭头代表什么意思后,也就足够应对 日常的工作和交流;同时,我们应该能将类图所表达的含义和最终的代码对应起来。
UML类关系图示例
请看以下这个类图,类之间的关系是我们需要关注的:
- 车的类图结构为<
>,表示车是一个抽象类; - 它有两个继承类:小汽车和自行车;它们之间的关系为实现关系,使用带空心箭头的虚线表示;
- 小汽车为与SUV之间也是继承关系,它们之间的关系为泛化关系,使用带空心箭头的实线表示;
- 小汽车与发动机之间是组合关系,使用带实心箭头的实线表示;
- 学生与班级之间是聚合关系,使用带空心箭头的实线表示;
- 学生与身份证之间为关联关系,使用一根实线表示;
- 学生上学需要用到自行车,与自行车是一种依赖关系,使用带箭头的虚线表示;
类之间的关系
泛化关系(generalization)
类的继承结构表现在 UML 中为:泛化(generalize)与实现(realize)。
继承指的是一个类(称为子类、子接口)继承另外的一个类(父类、父接口)的功能,并可以增加它自己的新功能的能力。
继承关系为 is-a
的关系,是类与类或者接口与接口之间最常见的关系之一。在 Java 中继承关系通过关键字 extends
明确标识,在设计时一般没有争议性。
在 UML 类图设计中,泛化关系用一条带空心箭头的直接表示。如下图表示(A继承自B):
注:表现在代码中,继承关系表现为一个类继承另一个类或者一个接口继承另一个接口。
实现关系(realization)
在 UML 类图设计中,实现关系用一条带空心箭头的虚线表示。如下图所示(A实现B):
实现指的是一个 class
类实现 interface
接口(可以是多个)的功能。实现是类与接口之间最常见的关系之一,在 Java 中实现关系通过关键字 implements
来表示。
注意:表现在代码中,实现关系表现为普通类实现某个接口。
聚合关系(aggregation)
在 UML 类图设计中,聚合关系用一条带空心菱形箭头的直线表示。如下图所示(A聚合到B上,或者说B由A组成):
聚合关系用于表示实体对象之间的关系,表示整体由部分构成的意思。
聚合是关联关系的一种特例,它体现的是整体与部分、拥有的关系,即 has-a
的关系,此时整体与部分之间是可分离的,他们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享。例如一个部门由多个员工组成。
注意:表现在代码中,和关联关系是一致的,只能从语义级别来区分。聚合与组合不同的是,整体和部分不是强依赖的,即使整体不存在了,部分仍然存在;例如,部门撤销了,人员不会消失,他们依然存在。
组合关系(composition)
在 UML 类图设计中,组合关系用一条带实心菱形箭头的直线表示。如下图表示(A组成B,或者B由A组成):
组合关系同样表示整体由部分组成的意思。与聚合关系一样,组合也是关联关系的一种特例,它体现的是一种整体与部分不可分割的关系,即 contains-a
的关系,这种关系比聚合更强,也称为强聚合。例如公司由多个部门组成组合,但此时整体与部分是不可分离的,整体的生命周期结束也就意味着部分的生命周期结束。
注意:表现在代码中,和关联关系是一致的,只能从语义级别来区分。组合关系是一种强依赖的特殊聚合关系,如果整体不存在了,则部分也就不存在了。例如,公司不存在了,部门也将不存在了。
关联关系(association)
在 UML 类图设计中,关联关系是用一条可能会有方向的直线表示的。关联关系默认不强调方向,表示对象间相互知道;如果特别强调方向,如下图所示(表示A关联B,但B不关联A):
关联关系体现的是两个类、或者类与接口之间语义级别的一种强依赖的结构关系,是一种长期的静态稳定的关系,通常与运行状态无关,一般由常识等因素决定的。
例如:乘车人和车票之间就是一种关联关系。
注意:表现在代码中,关联对象通常是以成员变量的形式实现的。
依赖关系(dependency)
在 UML 类图设计中,依赖关系是用一套带箭头的虚线表示的。依赖关系描述一个对象在运行期间会用到另一个对象的关系,如下图所示(A依赖于B)。
依赖关系是一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、临时性的、非常弱的,但是B类的变化会影响到A,与关联关系不同的是,它是一种临时性的关系,通常在运行期间产生,并且随着运行时的变化依赖关系也可能发生变化。
显然,依赖也有方向,双向依赖是一种非常糟糕的结构,我们总是应该保持单向依赖,杜绝双向依赖的产生。
注意:表现在代码中,依赖关系体现为类的构造方法及类方法的传入参数。
总结
对于继承、实现这两种关系没多少疑问,它们体现的是类和类、类与接口之间的纵向关系。其他的四种关系体现的是类与类、或者类与接口之间的引用、横向关系,是比较难区分的,有很多事物间的关系要想准确定位是很难的。前面也提到,这四种关系都是语义级别的,所以从代码层面并不能完全区分各种关系,但总的来说,后几种关系所表现的强弱程度依次为:组合>聚合>关联>依赖。
时序图
定义
时序图(Sequence Diagram)又名序列图、循序图,是一种UML交互图。时序图的重点是标记出某个行为的对象类和这些对象类之间所传递的消息及其时间顺序。另外时序图允许直观地表示出对象的生存期,在生存期内,对象可以对输入消息做出响应,并且可以发送消息。正是对象生存期的引入,时序图具备了时间顺序的概念,从而可以清晰地表示出对象在其生存期的某一个时刻的动态行为。这种时间概念的精确性使时序图在描述对象动态行为的时间特性方面具备了卓越的能力。
UML 时序图是一个二维图形。其中纵轴是时间轴,时间沿竖线向下延伸;横轴代表了在写作中个独立的对象。
基本元素
时序图包括的建模元素主要有:角色(Actor)、对象(Object)、生命线(Lifeline)、控制焦点(Focus of Control)、消息(Message)等等。
- 角色:系统角色,可以是人、及其甚至其他的系统或者子系统。
- 对象:对象代表时序图中的对象在交互中所扮演的角色。对象包括三种命名方式:
- 第一种方式包括对象名和类名;
- 第二中方式只显示类名不显示对象名,即表示他是一个匿名对象;
- 第三种方式只显示对象名不显示类名。
- 生命线:生命线是一条垂直的虚线,从对象底部延伸出来的,表示时序图中对象存在的时间。时序图中每个对象和底部中心都有一条垂直的虚线,这就是对象的生命线,对象间的消息存在于两条虚线间。
- 控制焦点:控制焦点是顺序图中表示时间段的符号,在这个时间段内对象将执行相应的操作,在时序图中每条生命线上的窄的矩形代表活动期。
- 消息:对象之间发出的交互,显示为箭头。消息一般分为同步消息(Synchronous Message)、异步消息(Asynchronous Message)和返回消息(Return Message):
- 同步消息:用实心箭头表示。消息的发送者把控制传递给消息的接收者,然后停止活动,等待消息的接收者放弃或者返回控制。用来表示同步的意义。
- 异步消息:用线性箭头表示。消息发送者通过消息把信号传递给消息的接收者,然后继续自己的活动,不等待接受者返回消息或者控制。异步消息的接收者和发送者是并发工作的。
- 返回消息:用虚线的线性箭头表示。返回消息表示从过程调用返回。