UML类图

参考链接:

《看懂UML类图和时序图》

什么是UML

面向对象的本质是抽象,当系统达到了超越其处理能力的程度,我们可以抽象出我们能够处理的范围来提成抽象级别,这样就可以构建更大、更复杂的系统。

现实世界和对象世界之间存在着一道沟壑,这道沟壑的名字叫抽象,抽象是面向对象的精髓所在,同时也是面向对象的困难所在。要跨越这道沟壑,我们需要解决以下问题:

  1. 一种把现实世界映射到对象世界的方法。
  2. 一种从对象世界描述现实世界的方法。
  3. 一种验证对象世界行为是否正确反映了现实世界的方法。

UML正是解决这一问题的分析设计方法。

当面向对象遇到这些问题的时候,UML统一建模语言出现了。学习UML只是学会了一门语言,而要写出一篇精彩的文章,却需要依靠写作人对生活的感悟和升华,这两者缺一不可。因此比学会UML建模本身更重要的是要理解UML背后所影藏的最佳实践。

UML统一建模语言要解决的问题

  1. UML既然是一门语言,作为语言要解决的首要问题就是沟通问题。
  2. 统一,则是要解决混乱的方言问题,如普通话一样被大家广泛认可。
  3. 可视化,容易被人理解和记忆(超越文字的表达方式)

建模实际上是一种对现实事物的理解。现实世界中如果我们站在很高的角度去抽象,就会发现无论这个事件多么复杂,其本质无非是由人、事、物和规则组成。

  1. UML采用称之为参与者(actor)的元模型作为信息来源提供者,代表现实中的“人”。
  2. UML采用称之为用例(use case)的一种元模型来表示驱动者的业务目标,也就是参与者想要做什么并且获得什么。代表现实中的“事”。
  3. 一件事怎么做,依据什么规则,则通过称之为业务场景(business scenario)和用例场景(use case scenario)的UML视图来描绘的。代表现实中的规则。
  4. 业务中的对象模型则就对应现实中的“物”

实现层类图

实现层类图是用的最普遍的类图,实现层类图位于设计阶段,这个阶段,类图可以视为伪代码。甚至可以用工具直接将实现层类图生成可执行代码。

本文使用UML建模工具《Visual Paradigm》(https://www.visual-paradigm.com)

实现关系

实现关系用一条带空心箭头的虚线表示,如下图接口A和类B:

UML实现关系

泛化关系

泛化关系表现为继承非抽象类(也就是说继承具体的实现类),如下图类B和C:

UML泛化关系

聚合关系

聚合关系用一条带空心菱形箭头的直线表示,如下图表示A聚合到B上,或者说B由A组成。

UML聚合关系

聚合关系用于表示实体对象之间的关系,表示整体由部分构成的语义;例如一个部门由多个员工组成。

与组合关系不同的是,整体和部分不是强依赖的,即使整体不存在了,部分仍然存在;例如, 部门撤销了,人员不会消失,他们依然存在。

组合关系

组合关系用一条带实心菱形箭头直线表示,如下图表示A组成B,或者B由A组成。

UML组合关系

与聚合关系一样,组合关系同样表示整体由部分构成的语义;比如公司由多个部门组成。

但组合关系是一种强依赖的特殊聚合关系,如果整体不存在了,则部分也不存在了;例如, 公司不存在了,部门也将不存在了。

关联关系

关联关系是用一条直线表示的;它描述不同类的对象之间的结构关系;它是一种静态关系, 通常与运行状态无关,一般由常识等因素决定的;它一般用来定义对象之间静态的、天然的结构; 所以,关联关系是一种“强关联”的关系。

比如,乘车人和车票之间就是一种关联关系;学生和学校就是一种关联关系。

关联关系默认不强调方向,表示对象间相互知道;如果特别强调方向,如下图,表示A知道B,但 B不知道A。

UML关联关系

在最终代码中,关联对象通常是以成员变量的形式实现的。

依赖关系

依赖关系是用一套带箭头的虚线表示的;如下图表示A依赖于B;他描述一个对象在运行期间会用到另一个对象的关系。

UML依赖关系

与关联关系不同的是,它是一种临时性的关系,通常在运行期间产生,并且随着运行时的变化; 依赖关系也可能发生变化。

显然,依赖也有方向,双向依赖是一种非常糟糕的结构,我们总是应该保持单向依赖,杜绝双向依赖的产生。

注:在最终代码中,依赖关系体现为类构造方法及类方法的传入参数,箭头的指向为调用关系;依赖关系除了临时知道对方外,还是“使用”对方的方法和属性。

适配器模式实例

适配器模式也称为包装器模式

UML适配器模式

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
12v电源接口
*/
interface Power12v{
void input(); //输入
void inputShap(); //形状
}

/**
220v电源插口
*/
class Power220vImpl{
public void output(){
System.out.println("输出220v电压")
}

public void outputShap(){
System.out.println("插口是三角插口")
}
}

/**
电源适配器
*/
class PowerAdapter extends Power220vImpl implements Power12v{

public void input(){
output();
System.out.println("这样我也能使用220v电压作为12v电源使用了")
}

public void inputShap(){
outputShap();
System.out.println("这样我也能使用圆角插口来适配三角接口了")
}
}

class Main{

public static void main(String[] args){
Power220vImpl power = new PowerAdapter();
power.input();
power.inputShap();
}
}

最后在这里摘抄一段《敏捷软件开发》原文:

你不应该认为设计就是一组和代码分离的UML图,一组UML图只是描绘了设计的一部分,但是它不是设计。软件项目的设计是一个抽象的概念,可以使用不同的媒介去描绘它,但它最终体现为源码。