系统设计:UML建模

UML静态建模

静态建模定义了系统中重要对象的属性和操作以及这些对象间的相互关系。主要包括类图、对象图、包图、构件图、部署图。

UML基础

类的表示:

第一行:类的名字,如果是接口<接口名>,如果是抽象方法则是斜体的

第二行:类的属性:

  • [开放程度][属性名称]:[类型]
  • +:public,-:private,#:protected,~:包权限,下划线:static

第三行:类的方法。

  • [开放程度][方法名称](参数):返回类型
  • 斜体:抽象方法

UML类图

只有知道对方信息,箭头才能指向对方。

1566180926318

泛化关系

抽象语义

用来描述继承关系,在Java中使用extends关键字。

img

代码语义

  • 继承extends关系。

实现关系

抽象语义

用来实现一个接口,在 Java 中使用implements关键字。或者可以说是接口的一个实现

img

代码语义

  • implements

关联关系

抽象语义

表示不同类对象之间有关联,这是一种静态关系,与运行过程的状态无关,在最开始就可以确定。因此也可以用1对1、多对1、多对多这种关联关系来表示。比如学生和学校就是一种关联关系,一个学校可以有很多学生,但是一个学生只属于一个学校,因此这是一种多对一的关系,在运行开始之前就可以确定。

双向关联有两个箭头或者没有箭头。而单向关联有一个箭头,表示关联的方向

img

代码语义

关联是实打实的关系,因此是实线,并且其作为一个实例属性存在。

它们存在业务的联系,用来表示无法用聚合和组合表示的关系,因此不是组合或者聚合。

  • 一个类当中,有另外一个类作为属性。用来表示无法用聚合和组合表示的关系。如学生与老师的关系
  • 关联是一种拥有的关系, 它使一个类知道另一个类的属性和方法,其暗示了依赖关系。
    • 例如企鹅与气候,企鹅是需要知道气候的变化,需要了解气候规律的。即一个类知道另一个类。

依赖关系

抽象语义

一个类要借助另一个类来实现功能。

和关联关系不同的是,依赖关系是在运行过程中起作用的,是一种使用的关系, 即一个类的实现需要另一个类的协助, 所以要尽量不使用双向的互相依赖。A 类和 B 类是依赖关系主要有三种形式:

img

代码语义

依赖是虚拟的,只在使用时关注,因此是虚线并在方法当中作为变量使用。

  • A类是B类方法的局部变量。
  • A类是B类方法当中的一个参数。
  • 依赖通常体现为调用一个其他所依赖类的方法,A类向B类发送消息,从而影响B类发生变化。

聚合关系

抽象语义

聚合:是整体与部分的关系, 且部分可以离开整体而单独存在. 如车和轮胎是整体和部分的关系, 轮胎离开车仍然可以存在.

两者具有独立的生命周期。

img

  • 成员可独立。班级与学生

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

img

在代码实现聚合关系时,成员对象通常作为构造方法、Setter方法或业务方法的参数注入到整体对象中,图6对应的Java代码片段如下:

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

代码语义

  • 一个成员变量。

组合关系

抽象语义

两个对象具有相同的生命周期。

组合:是整体与部分的关系, 但部分不能离开整体而单独存在. 如公司和部门是整体和部分的关系, 没有公司就不存在部门.

img

  • 成员不可独立。汽车与引擎(必须依赖于整体才有意义)

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

img

在代码实现组合关系时,通常在整体类的构造方法中直接实例化成员类,图7对应的Java代码片段如下:

1
2
3
4
5
6
7
8
9
10
`public class Head { 	
private Mouth mouth;
public Head() {
mouth = new Mouth(); //实例化成员类
}
……
}
public class Mouth {
……
} `

代码语义

  • 作为成员变量。

实战

泛化 = 实现 > 组合 > 聚合 > 关联 > 依赖

image.png

下面围绕类Library类分析下这个图,首先library通过组合方式关联到了Catalog类目类,这说明类目不能独立存在要依赖图书馆存在,所以这里没有使用聚合而使用了组合。另外library通过聚合关联到了Book Item 类和Account账号类,这说明图书馆是有0个或者多个图书和账户组成,这里使用聚合而不是用组合是因为书和账号可以独立于图书馆存在,比如我有学号账号,但是图书馆里面不是必然有你的账号。

下面围绕Catalog分析,类目通过双向关联关联到bookitem,说明一个类目里面可能会有0个或者多个书籍,一个书籍对应着一个类目。另外类目有通过realization实现了search类和manage类的接口,让类目有搜索和管理功能。Search类搜索时候会依赖Patron类图书捐赠人的姓名地址或者Libraian类图书管理员的姓名地址,职位。 图书管理类时候会依赖图书管理员类的信息。

而Patron图书捐赠人有可能是一个学生,学生有自己的账号,所以patron类会聚合到Account.
bookItem类通过泛化继承Book中书的共性部分信息。有通过关联关联到了account,说明一个账户只能接到0本和最多12本书,最多可以预定3本书。

最后Book类双向关联到Author类,数目一个作者至少写了1本书(严格说应该是0),一本书至少有一个作者编写,
Account账户类有依赖一个AccountState的枚举值的类用来存放账号状态。

参考