统一建模语言UML及类图关系

UML 即统一建模语言,是目前最常用的建模工具,已成为当今软件设计的标准图标式设计语言。

所谓统一,指的是在 UML 之前,软件建模工具和方法有很多种,最后业界达成共识,用 UML 统一软件建模工具。

所谓建模,就是用 UML 对领域业务问题和软件系统进行设计抽象,一个工具完成软件开发过程中的两个客观存在的建模。

什么是 UML

UML 语言具有以下重要功能:

可视化功能

可视化(Visualizing)功能:可以促进对问题的理解和解决,便于熟悉 UML 的设计师彼此交流和沟通。

可以较容易地发现设计草图中可能的逻辑错误,避免和减少意外发生。

说明功能

说明(Specifying)功能:UML 为系统设计提供了一种通用的,精确的,没有岐义的说明方案。

建造功能

UML 有它自己的语法规则,这使得人们可以使用建模工具软件对一个系统设计模型加以解释,并将设计模型映射到一种计算机语言(如 Java)上。

也就是说,使用一种建模工具可以大大加块建模和系统设计的过程。

建文档功能

使用 UML 进行设计可以同时产生系统设计文档。基于 UML 文档,可以降低工程师学习成本,使修改工作事半功倍,降低运维成本。

常用的UML视图

UML 规范了十多种模型视图,常用的有以下视图:

  • 类图(Class Diagrams):描述一些类,包的静态结构和它们之间的静态关系。
  • 序列图(Sequence Diagrams):是一种相互作用的图,描述不同对象之间信息传递的时序。
  • 组件图(Component Diagrams):描述可以部署的软件组件(如,jar文件,EJB等)之间的静态关系。
  • 部署图(Deployment Diagrams):描述一个系统的拓扑结构。
  • 用例图(Use Case Diagrams):描述一系列的角色和使用案例及它们之间的关系。可以用来对一个系统的最基本的行为进行建模。
  • 状态图(Statechart Diagrams):描述一系列对象的内部状态及状态的变化和转移。注意一个类不能有两个不同的状态图。
  • 活动图(Activity Diagrams):描述不同的过程之间的动态接触。活动图是使用案例图所描述的行为的具体化。
  • 合作图(Collaboration Diagrams):是一种相互作用的图,描述发出信息,接收信息的一系列对象的组织结构。

所有这些图里面,案例图、类图和序列图是最为有用的。

根据这些图的用意,可以将它们大体上划分为 结构型图行为型图 两种.

  • 结构型图:描述了系统的静态结构,在显示一个系统已有的类及它们之间的静态关系时最为有用。

    包括:类图,对象图,构件图,部署图

  • 行为型图:描述了一个系统的动态性质,在显示系统的元素如何协作产生满足要求的系统行为方面最为有用。

    包括:使用案例图,活动图,状态图,时序图,合作图。

显然,要描述一个设计模式的行为特性,使用 状态图序列图 就行合适。

UML视图的设计应用

用类图设计对象模型

一个类图的框是通常有分三层的,包括:类名、属性列表、方法列表。类图描述类之间的静态关系。

Java 开发使用 IDEA 平台,可以右键生成类的类图。

类之间的关系

类之间的关系有实现(Realization),泛化(Generalization),关联(Association),聚合(Aggregation),组合(Composition),依赖(Dependency)。

其中,聚合(Aggregation),组合(Composition)属于关联(Associate),是特殊的关联(Associate)关系。

关系强度(耦合度)由高到低为:泛化 = 实现 > 组合 > 聚合 > 关联 > 依赖

实现关系

实现关系(realization):是类之间的语方关系,其中的一个类指定了由另一个类保证执行的契约

在 Java 语方中,实现用来表示类与接口、抽象类与接口之间的关系;描述具体类或抽象类实现接口。

图形:用 实心三角形箭头 + 虚线 表示,箭头指向接口。

实现关系

泛化关系

泛化关系(generalization):是一般与特殊化的关系,描述特殊元素的对象可替换一般元素的对象。

Java 语言中的多态是泛化的一种具体实现。而 继承(extends)关系是泛化的一种实现方式。

在继承上理解泛化:泛化可用来表示类与类、类与抽象类、抽象类与抽象类、接口与接口之间的继承关系。是从子类指向父类的,或从具体指向抽象。

图形:用 实心三角形箭头 + 实线 表示,箭头指向父类或父接口。

泛化关系

依赖依关

依赖关系:表示一个类依赖于另一个类。是类与类之间的连接,依赖总是单向的。

图形:用虚线箭头表示,箭头指向被依赖的对象。

依赖关系

一般而言,依赖关系在 Java 语言中体现为 局部变量,方法的入参,以及对静态方法的调用。换而言之,一个类 A 的某一个局部变量的类型是另一个类 B,那么 类 A 就依赖于 类 B。

  • 如果一个方法的参量是另一个类 B 的实例,那么这个方法所在的类 A 依赖于 类 B。

  • 如果一个类 A 调用另一个类 B 的静态方法,那么类 A 依赖于 类 B。

如果类 B 出现在类 A 的实例变量中(构造方法入参),那么 类 A 与 类 B 的关系就 超越 了依赖关系,而变成了某一种关联关系。

代码示例:

1
2
3
4
5
6
7
8
public class Dog {
// 依赖 Water
public void drink(Water water){
}
}

public class Water {
}

关联关系

关联关系:是类与类之间的一种结构关系,它使一个类知道另一个类的属性和方法

两个类是处在同一层次上的,是平等的,表示的是两个同等地位类之间的结构关系

关联可以是单向的,也可以是双向的。单向的关联更为普遍,通常不建议使用双向关联。

关联有两元关系和多元关系。两元关系 指一种 一对一的关系,多元关系是 一对多多对一的关系。

在 Java 语言里,关联关系是使用实例变量实现的。关联有一个方向箭头,表明关联的目标对象。

在每一个关联的端点,还可以有一个基数(Multiplicity),表明这一端的类可以有几个实例。

1
2
3
4
5
6
public class Company {
private List<Employee> employeeList;
}

public class Employee {
}

一个关联关系往往可以进一步确定为聚合或者合成关系。简单的 关联关系 比较少见。

聚合关系

聚合关系:是关联关系的一种,是较强的的关联关系,强调整体与部分之间的关系。体现为 A可以包含 B,但 B 不一定是 A 的一部分。

聚合 的整体和部分之间在生命周期上没有必然的联系,部分对象可以在整体对象创建之前创建,也可在整体对象销毁之后的销毁。整体与部分是可以独立存在的。

关联关系一样,聚合也是通过实例变量实现的。但是,关联关系所涉及的两个类是处在同一层次的,而在聚合关系中,两个类是处在不平等的层次上的,一个代表整体,另一个代表部分。

关联与聚合仅仅从 Java 语法上是分辨不出的,需要考察所涉及的类之间的逻辑关系。

图形:用空心菱形 + 实线箭头表示,菱形指向整体。(IDEA没有区分空心菱形和实心菱形)

聚合关系

1
2
3
4
5
6
7
8
9
10
public class Car {
private Engine engine;
private List<Wheel> wheelList;
}

public class Engine {
}

public class Wheel {
}

示例:汽车类与引擎类、轮胎类,以及其他零件类之间的关系,便是整体和个体的关系。

组合关系

组成关系:是关联关系的一种,是比聚合关系强的关系,强调整体与部分的生命周期是一致的,整体负责部分的生命周期的管理(整体的对象负责代表部分的对象的生命周期),合成关系是不能共享的。

用来表示整体与部分的关系,是一种强的关联关系,整体和部分的生命周期一致。

生命周期一致:指部分必须在组合创建的同时或之后创建,在组合销毁之前或者同时销毁,部分的生命周期不会超出组合的生命周期。

代表整体的对象需要负责保持部分对象的存活,在一些情况下负责将代表部分的对象消亡。代表整体的对象可以将代表部分的对象传递给另一个对象,由后都负责此对象的生命周期。

换而言之,代表部分的对象在每一个时刻只能与一个对象发生合成关系,由后者排他地负责其生命周期。

图形:用实心菱形+实线箭头表示,菱形指向整体。(IDEA没有区分空心菱形和实心菱形)

组合关系

示例:订单类 和 订单详情类,订单对象负责订单详情的生命周期,并且订单详情不能共享给其它订单。

聚合与组合区别

聚合关系has-a 关系,组合关系contains-a 关系。聚合关系表示整体与部分的关系比较弱,整体与部分可以独立存在;而组合比较强,整体负责部分的生命周期管理。

一个明显差别是,组合中的部分在同一刻只能属于一个整体,是不可共享的;而聚合的一个部分对象可以被多个其它整体对象聚合。

实现方式区别

  • 实现关系:implements
  • 泛化关系:extends (继承)
  • 依赖关系:关系对象出现在局部变量或者方法的入参中,或者关系类的静态方法被调用
  • 关联关系:关系对象出现在实例变量
  • 聚合关系:关系对象出现在实例变量
  • 组合关系:关系对象出现在实例变量

用序列图描述系统调用

序列图则用来描述参与者之间的动态调用关系。

每个参与者都有一条垂直向下的生命线,用虚线表示;参与者之间的消息是从上到下表示其调用的前后顺序关系。

每个参与者都有一个激活条,在生命线上用细长钜形条表示,只有参与者活动的时候才激活。

正向调用使用实线实心箭头表示,返回使用虚线虚箭头表示。

序列图

用组件图进行模块设计

组件是比类粒度更大的设计元素,一个组件通常包含多个类。通常用来描述物理上的组件,如果一个 Jar,一个 DDL 等。

在实践中,进行模块设计时更多的是用组件图。。

组件图描述组件之间的静态关系,主要是依赖关系。因为组件的粒度比较粗,通常用以描述软件的模块及其之间的关系,需要在设计早期阶段画出来,因此组件图一般用在概要设计阶段。

用部署图描述物理架构

部图图描述软件系统的最终部署情况。比如需要多少台机构,关键组件或服务分别部署在哪些服务器上。

部署图是软件系统最终物理呈现的蓝图,可以清晰地了解到最终运行的系统物理上的样子,还可以估算服务器的成本。

部署图是整个软件设计模型中比较宏观的一种图,主要用在概要设计阶段。

用例图进行需求分析

用例图通过反映用户和系统的交互来描述系统的功能需求。主要用在需求阶段。

一张用例图可能只包含其中一小部分功能,这些功能被矩形框起来,这个矩形框被称为用例的边界。框里的椭圆表示一个个功能,功能之间既可以调用依赖,也可以进行功能扩展。

用状态图描述对象状态变迁

状态图用来展示单个对象生命周期的状态变迁。

一张状态图描述一个生命周戎的各种状态及其变迁的关系。

状态图要在需求分析阶段画,描述状态变迁的逻辑关系;在详细设计阶段也要画,这个时候要用枚举值表示,以指导具体的开发。

用活动图描述调用流程

活动图主要用来描述过程逻辑和业务流程。UML 中没有流程图,很多时候用活动图代替流程图。

活动图和流程图的图形元系很接近,实心圆代表开始,空心圆代表结束,圆角矩形代表活动,菱形表示分支判断。

活动图引入了 泳道 的概念。活动图可以根据活动的范围,领域,系统,角色等将活动划分到不同的泳道中,使流程边界更加清晰。活动图跨职能图 可以说是完成一致。

作者

光星

发布于

2021-01-05

更新于

2022-07-07

许可协议

评论