UML2.5 统一建模语言
UML 是一种开放的方法,用于说明、可视化、构建和编写一个正在开发的、面向对象的、软件密集系统的制品的开放方法。UML展现了一系列最佳工程实践,这些最佳实践在对大规模,复杂系统进行建模方面,特别是在软件架构层次已经被验证有效。
类图
面向对象程序设计(Object-Oriented Programming, 缩写为 OOP) 是一种范式, 其基本理念是将数据块及与数据相关的行为封装成为特殊的、 名为对象的实体, 同时对象实体的生成工作则是基于程序员给出的一系列蓝图, 这些蓝图就是类,在UML中,类图专门是用来描述这种实体的。如下图所示:
类之间是有相互关系的,就像猫属于动物,动物和植物又属于生物体:
类之间的关系可以更细分的划分为这几种:依赖,关联,聚合,组合。
依赖
依赖是类之间最基础的、也是最微弱的关系类型。 如果修改一个类的定义可能会造成另一个类的变化,那么这两个类之 间就存在依赖关系。当你在代码中使用具体类的名称时, 通 常意味着存在依赖关系。 例如在指定方法签名类型时, 或是通过调用构造函数对对象进行初始化时等。 通过让代码依赖接口或抽象类(而不是具体类),你可以降低其依赖程度。
通常情况下,UML 图不会展示所有依赖——它们在真实代码中的数量太多了。 为了不让依赖关系破坏 UML 图, 你必须对其进行精心选择,仅展示那些对于沟通你的想法来说重要 的依赖关系。
在UML中,依赖关系用一个虚线的箭头表示,从依赖者到被依赖者,例如教授依赖课程资料:
关联
关联是一个对象使用另一对象或与另一对象进行交互的关系。 在 UML 图中, 关联关系用起始于一个对象并指向其所使用 的对象的简单箭头来表示。 顺带一提, 双向关联也是完全正常的, 这种情况就用双向箭头来表示。 关联可视为一种特殊类型的依赖,即一个对象总是拥有访问与其交互的对象的权限,而简单的依赖关系并不会在对象间建立永久性的联系。
一般来说, 你可以使用关联关系来表示类似于类成员变量的东西。这个关系将一直存在,因此你总能通过订单来获 取其顾客。 但是它并非一定是成员变量。如果你根据接口来创建类,它也可以表示为一个可返回订单的顾客的方法。
为了区分关联和依赖,举如下的例子,Professor 依赖 Course 提供的 c.getKnowledge 方法获取知识,将其传授给关联的 Student:
1 | class Professor is |
如果有人修改了 课程 类的 getKnowledge (获取知识)方法(修改方法名或添加一些 必须的参数等),代码将会崩溃。这就是依赖关系。
让我们来看看名为 student (学生)的成员变量,以及如何在 teach 方法中使用该变量。我们可以肯定学生 (Student)类是教授类的依赖: 如果 remember 方法被修改, 教授的代码也将崩溃。但由于教授的所有方法总能访问 student 成员变量,所以学生类就不仅是依赖,而也是关联了。
UML图中,经常用一个单向的箭头表示关联关系:
聚合
聚合是一种特殊类型的关联, 用于表示多个对象之间的一对多、多对多或整体对部分的关系 。 普通关联仅用于描述两个对象之间的关系。通常在聚合关系中, 一个对象拥有 一组其他对象, 并扮演着容器或集合的角色。组件可以独立于容器存在, 也可以同时连接多个容器。 在 UML 图中,聚合关系使用一端是空心菱形,另一端指向组件的箭头来表示。
组合
组合是一种特殊类型的聚合, 其中一个对象由一个或多个其他对象实例构成。 组合与其他关系的区别在于组件仅能作为容器的一部分存在。 在 UML 图中,组合与聚合关系的符号相同,但箭头起始处的菱形是实心的。
OOP
面向对象程序设计的四个基本概念使其区别于其他程序设计范式,他们分别是:抽象,多态,封装以及继承。
抽象
当使用面向对象程序设计的理念开发一款程序时, 我们会将大部分时间用于根据真实世界对象来设计程序中的对象。但是,程序中的对象并不需要能够百分之百准确地反映其原型(极少情况下才需要做到这一点)。实际上,你的对象只需模拟真实对象的特定属性和行为即可,其他内容可以忽略。
例如, 飞行模拟器和航班预订程序中都可能会包含一个飞机 Airplane 类。 但是前者需包含与实际飞行相关的详细信息,而后者则只关心座位图和哪些座位可供预订。
抽象是一种反映真实世界对象或现象中特定内容的模型, 它 能高精度地反映所有与特定内容相关的详细信息, 同时忽略其他内容。
封装
封装是指一个对象对其他对象隐藏其部分状态和行为, 而仅向程序其他部分暴露有限的接口的能力。
如果想要启动一辆车的发动机, 你只需转动钥匙或按下按钮即可, 无需打开引擎盖手动接线、转动曲轴和气缸并启动发动机的动力循环。 这些细节都隐藏在引擎盖下,你只会看到一些简单的接口: 启动开关、方向盘和一些踏板。
对象的接口——它是对象的公有部分,能够同其他对象进行交互。
封装某个内容意味着使用关键字 private 来对其进行修饰, 这样仅有其所在类中的方法才能访问这些内容。 还有一种限制程度较小的关键字 protected 保护 , 其所修饰的对象仅允许父类访问其类中的成员。
绝大部分编程语言的接口和抽象类(或方法)都基于抽象和 封装的概念。 在现代面向对象的编程语言中, 接口机制(通常使用 interface 或 protocol 关键字来声明)允许你定义对象之间的交互协议。这也是接口仅关心对象行为,以及你不能在接口中声明成员变量的原因之一。
假如航空运输 FlyingTransport 接口中有一个 fly(origin, destination, passengers) 方法 (即以起点、 终点以及乘客为参数的飞行方法)。 在设计航空运输模拟器时, 你可以对机场 Airport 做出限制, 使其仅与实现了航空运输接口的对象进行交互。此后,你可以确保 传递给机场对象的任何对象——无论是飞机、 直升机、还是可怕的家养狮鹫 —— 都能到达或离开这种类型的机场。
继承
继承是指在根据已有类创建新类的能力。 继承最主要的好处是代码复用。如果你想要创建的类与已有的类差异不大, 那也没必要重复编写相同的代码。你只需扩展已有的类并将额外功能放入生成的子类(它会继承父类的成员变量和方法) 中即可。
使用继承后,子类将拥有与其父类相同的接口。如果父类中声明了某个方法,那么你将无法在子类中隐藏该方法。你还必须实现所有的抽象方法,即使它们对于你的子类而言没有意义。
在绝大多数编程语言中, 子类仅能对一个父类进行扩展。 另一方面, 任何类都可以同时实现多个接口。 但是正如我之前提到的那样, 如果父类实现了某个接口, 那么其所有子类都 必须实现该接口。
多态
绝大部分动物 Animals 可以发出声音。 我们需要所有子类都重写基类的 makeSound 发出声音方法,让每个子类都发出正确的声音,因此我们可以马上将其声明为抽象。 这让我们得以忽略父类中该方法的所有默认实现,从而强制要求所有子类自行提供该方法的实现。
假如将几只猫和狗放入一个大袋子中。 然后,我们闭上眼睛,将动物一个一个地从袋中取出。 我们并不知道自己取出的是何种动物。 但如果我们好好地摸摸它们的话, 它就会根据自己的具体类发出特殊的欢快叫声。
1 | bag = [new Cat(), new Dog()]; |
程序并不知道 a 变量中所包含的对象的具体类型,但幸亏有被称为多态的特殊机制, 程序可以追踪对象的子类并调用其方法,从而执行恰当的行为。
多态是指程序能够检测对象所属的实际类,并在当前上下文不知道其真实类型的情况下调用其实现的能力。
UML
UML图经过各种大型工程的实践,被证明是一种极其有用的方式来描述可视化系统,数据可系统及其他软件系统,所有的软件开发人员都应该学习并掌握它。从种类上来说,它有以下几种类型:
类图(Class Diagram)
Class 经常被用用来描述某个具体的或者抽象的对象,这个对象经常具有一些属性和方法,而且这些属性和方法都具有不同的访问限制规则,例如一个用来描述 Dog 的类图:
可以看到的是在每个属性或者方法之前都有一个 + 或者 -,这个就是访问限制规则,一共有四种:
+:Public,可公开访问-:Private#:Protected~:Package Local
而且对于方法而言,可以通过 in,inout 或者 out 标识参数的意义:
in: 该参数仅作为输入参数,不应该被修改;inout: 该参数即可作为输入参数,也可以被内部修改;out: 该参数仅用于作为输出参数存储库,就像传入一个地址,然后内部可以对其进行赋值;
就像现实世界中不同对象之间有不同的关系一样,类图中也有描述不同类之间关系的方式,一般存在六种关系,分别是关联,继承,实现,依赖,聚合和组合。
例如,学生从老师那里学习知识,这种关系就可以表示位简单的关联关系,在表示的时候使用一个联系表示即可,也可以适当添加描述信息:
继承有时候也可以称为泛化,用一个空心箭头从子类指向父类,父类可能是抽象类或者具体类:
实现一般是指具体类型和接口之间关系,用一个虚线实心箭头表示:
当一个对象在其方法中使用另一个类的对象,并且未存储在任何字段中时,就表示存在依赖关系,例如,Person 有一个方法 Read 接收一个 Book 的实例 book 作为参数,调用 Book 的 getknowledge 方法获取知识:
聚合和组合比较相近,都表示一对多的关系,而聚合通常用来表示用类的聚合,而组合表示整体和部分的关系;例如学校有很多老师,这种表示聚合关系;而学校也有很多不同的学院,计算机学院,土木工程等,这种表示组合关系,不同类型;在表示上聚合使用空心菱形箭头,组合使用实心菱形箭头表示。
类图是UML 结构图,它在类和 接口 级别显示设计系统的结构 ,显示它们的特性、 约束 和关系—— 关联、 泛化、 依赖等。常见的类图有:领域模型图、实现类图。
领域模型图:
实现类图:
标准UML类的构造形态
| 名称 | 描述 |
|---|---|
«Auxiliary» |
辅助类是支持核心或基础类的类,通常通过实现辅助逻辑或控制流来支持。 辅助支持的类可以使用焦点类显式定义,也可以通过依赖关系隐式定义。辅助类通常用于在设计阶段指定组件的辅助业务逻辑或控制流。 |
«Focus» |
焦点是定义一个或多个支持类的核心逻辑或控制流的类。 支持类可以使用辅助类显式定义,也可以通过依赖关系隐式定义。焦点类通常用于在设计阶段指定组件的核心业务逻辑或控制流。 |
«ImplementationClass» |
在某些编程语言(例如 C++、Smalltalk、Java)中类的实现,其中一个实例不能有多个类。这与 UML 类相反,在 UML 类中,一个实例可能同时具有多个类,并且随着时间的推移可能会获得或丢失类,而一个对象可能会动态地具有多个类。一个实现类可以实现多种不同的类型。 实现类的物理属性和关联不必与其实现的任何分类器的物理属性和关联相同,并且实现类可以根据其物理属性和关联为其操作提供方法。 |
«Metaclass» |
其实例也是类。 |
«Type» |
类型是指定对象域以及适用于对象的操作的类,但不定义这些对象的物理实现。类型可以具有属性和关联。 类型操作的行为规范可以使用例如活动图来表达。 一个对象最多可以有一个实现类,但是它可以符合多种不同的类型。 |
«Utility» |
工具类是仅具有类范围的静态属性和操作的类。 因此,工具类通常没有实例。 |
类的模版
UML 类可以被模板化或绑定。下面的示例显示了具有两个形式模板参数的模板类 Array。 第一个模板参数 T 是不受约束的类模板参数。 第二模板参数n是整数表达式模板参数。绑定类 Customers 的模板绑定将无约束类 T 替换为类 Customer,边界 n 替换为整数值 24。因此,绑定类 Customers 是包含 24 个 Customer 类对象的数组。
接口
接口是一个 分类器 ,声明一组连贯的公共功能和义务。接口指定契约。实现(实现)接口的任何分类器实例都必须履行该契约,从而提供契约所描述的服务。由于接口是声明,因此它们不可实例化。相反,接口规范是通过可实例化分类器的实例来实现的,这意味着可实例化分类器呈现出符合接口规范的公共外观。任何给定的分类器都可以实现多个接口。接口可以由许多不同的分类器来实现。接口可以使用矩形符号来显示,并且名称前面带有关键字“interface”。
数据类型
数据类型是一个分类器(类似于类), 其实例“仅通过其值来标识”。数据类型的典型用途是表示业务领域的 值类型、编程语言的原始类型或结构化类型。例如,日期/时间、性别、货币、地址可以定义为数据类型。数据类型实例的所有副本以及具有相同值的该数据类型的任何实例都被视为相等实例。数据类型使用带有关键字<<dataType>>的矩形符号显示。数据类型可以包含 支持结构化数据类型 建模的属性 和操作。如果结构相同并且相应属性的值相等,则结构化数据类型的实例被认为是相等的。当数据类型被引用时,例如,作为类属性的类型,它简单地显示为数据类型的名称。
原始数据类型是表示原子数据值(即没有部分或结构的值)的数据类型。原始数据类型可以具有在 UML 外部定义的精确语义和操作,例如数学上的, 标准 UML 原始数据类型包括: Boolean、Integer、UnlimitedNatural、String、Real,原始数据类型的实例没有标识。如果两个实例具有相同的表示,那么它们是无法区分的。原始数据类型在原始数据类型名称上方或之前有关键字<<primitive>>。
枚举是一种数据类型,其值在模型中作为用户定义的枚举文字。可以使用带有关键字«enumeration» 的分类器符号(矩形)来显示枚举。枚举的名称位于上部隔间中。列出枚举属性的隔间放置在名称隔间下方。列出枚举操作的隔间放置在属性隔间下方。可以将枚举文字列表逐行放置在底部隔间中。属性和操作隔间可以被限制,并且通常如果它们是空的则被限制。
UML属性
属性是一种结构特征,属性表示分类器结构的某些命名部分。例如,Patient 类可以将 id、姓名、性别、出生日期等作为其属性。创建分类器的实例时,每个非静态属性都成为该实例状态的一部分,并通过将属性名称映射到构成实例状态的一个或多个特定值来实现。每个属性的值都有特定的类型,并分配在实例的槽中或与该实例关联。
属性的一般语法如下所示:
属性::= [可见性] [‘/‘] 属性名称 [ ‘:’属性类型 ] [ ‘[‘多重性 ‘]’ ] [ ‘=’默认值] [属性修饰符]
可见性::= ‘ +’ | ‘~’| ‘#’| ‘-‘
属性修饰符::= ‘{‘属性修饰符 [ ‘,’ 属性修饰符] * ‘}’
属性修饰符::= ‘id’ | ‘只读’ | ‘已订购’ | ( ‘seq’ | ‘序列’ ) | ‘独特’| ‘非独特’ | ‘联盟’ | “重新定义” 属性名称 | ‘子集’ 属性名称 | 属性约束
请注意,没有默认的可见性。此外,即使可见性在模型中具有某些值,也可能会抑制在图表上显示可见性。因此,如果图表上未显示可见性,则说明它未指定或被限制。正斜杠“/”表示该属性是 派生的。属性类型是由分类器名称表示,属性可以有多重性。多重界限,限制属性值集合的大小。默认情况下最大界限为 1。默认值 选项是属性的默认值或值的表达式。属性修饰符:
| 修饰符 | 描述 |
|---|---|
| id | 属性是拥有该属性的类的标识符的一部分。 |
| readOnly | 属性是只读的(isReadOnly = true)。 |
| ordered | 属性是有序的 (isOrdered = true)。 |
| nonunique | 多值属性没有重复值 (isUnique = true)。 |
| nonunique | 多值属性可能具有重复值 (isUnique = false)。 |
| sequence (or seq) | 属性是一个有序包(isUnique = false 且 isOrdered = true)。 |
| union | 属性是其子集的派生联合。 |
| redefines property-name | Property 重新定义了名为property-name的继承属性。 |
| subsets property-name | Property 是名为property-name的属性的子集。 |
| property-constraint | 适用于属性的约束 |
分类器拥有的属性 表示分类器的属性。属性的上下文是所属分类器。允许使用关联表示法来显示属性:
关联的所有权结束于关联的 Patient 类,由小实心圆圈(也称为点)以图形方式表示。另请注意,连接到类的关联端没有修饰。当属性是关联端时,属性的一个或多个值与关联另一端的一个或多个实例相关。关联拥有的属性代表关联的属性,并命名为member end。在关联端上下文中是关联的另一端或两端的类型集。当关联端由分类器 拥有时,分类器 属性可以表示该关联端。关联分类器对关联端的所有权可以通过小实心圆(又名点) 以图形方式表示 。点绘制在直线与分类器相交的点处。它可以解释为表明该模型包含由点所触及的分类器表示的类型的属性。该属性由另一端的分类器拥有。
UML操作
操作是一种行为特征,可能由接口、 数据类型或类 拥有。操作也可以被 模板化 并用作模板参数。可以在其特征分类器的实例上直接调用操作。 该操作指定此类调用的 名称、类型、参数和约束。operation ::= [ visibility ] signature [ oper-properties ]。 操作的可见性是可选的,如果存在,它应该是以下之一:visibility ::= '+' | '-'| '#'| '~' ,操作的签名具有可选的参数列表和返回规范。
signature ::= operation-name '(' [ parameter-list ] ')' [ ':' return-spec ]
operation-name是操作的名称。参数列表是操作的参数列表,格式如下:
parameter-list ::= parameter [ ',' parameter ]*parameter ::= [ direction ] parm-name ':' type-expression [ '[' multiplicity ']' ] [ '=' default ] [ parm-properties ]
parm-name是参数的名称。type-expression是指定参数类型的表达式。重数是参数的重数。Default 是一个表达式,定义参数默认值的值规范。
操作的属性是可选的,如果存在应遵循规则:
oper-properties ::= '{' oper-property [ ',' oper-property ]* '}'oper-property ::= 'redefines' oper-name | 'query' | 'ordered' | 'unique' | oper-constraint
操作的属性一般定义为:
redefines oper-name- 操作重新定义由操作名标识的继承操作;query- 操作不会改变系统的状态;ordered- 返回参数的值是有序的;unique- 参数返回的值没有重复项;oper-constraint- 是应用于操作的约束。
UML多重性和多重性元素
UML中的多重性允许指定某些元素集合的基数(即元素数量)。多重性元素 定义了一些元素的集合,并且包括多重性以及集合元素的顺序和唯一性的规范。多重性是某些元素集合的基数(即元素数量)的定义,通过提供非负整数的包含区间来指定所描述元素的允许实例数。重数区间有一些下限和上限。
1 | multiplicity-range ::= [ lower-bound '..' ] upper-bound |
下限和上限可以是自然常量或计算为自然(非负)数的常量表达式。上限也可以指定为星号“*”,表示元素数量不受限制。上限应大于或等于下限。
| 多重性 | 选项 | 基数 |
|---|---|---|
| 0..0 | 0 | 集合必须为空 |
| 0..1 | 无实例或只有一个实例 | |
| 1..1 | 1 | 恰好有一个实例 |
| 0..* | 零个或多个实例 | |
| 1..* | 至少一个实例 | |
| 5..5 | 5 | 恰好 5 个实例 |
| m..n | 至少 m 但不超过 n 个实例 |
如果多重性与符号为文本字符串(例如类属性) 的元素关联,则多重性范围将作为该文本字符串的一部分放在方括号内。
如果多重性与显示为符号(例如用例或类) 的元素关联 ,则显示多重性范围时不带方括号。
多重性元素定义了一些元素的集合,并且包括多重性 以及集合元素的顺序和唯一性的规范。多重性元素的一些子类是 结构特征、 操作、 参数、引脚。集合属性可以使用以下非规范语法规则来描述:
1 | collection-type ::= multiplicity-range [ '{' collection-options '}' ] |
集合选项指定元素实例化中的值是否应该是唯一的和/或有序的:
1 | collection-options ::= order-designator [ ',' uniqueness-designator ] | uniqueness-designator [ ',' order-designator ] |
如果多重性元素是多值的并且指定为有序的,则该元素的实例化中的值的集合是按顺序排序的。默认情况下,集合没有排序。如果多重性元素是多值的并且指定为unique,则该元素实例化中的值集合中的每个值都必须是唯一的。默认情况下,集合中的每个值都是唯一的。
UML约束
约束是一个可封装的元素,它表示与某个元素 (拥有该约束)或多个元素相关的某些条件、限制或断言。约束通常由布尔表达式指定,该表达式的计算结果必须为 true 或 false。系统的正确设计必须满足约束(即评估为true)。约束通常用于类图上的各种元素。一般来说,约束有多种可能的所有者。所属元素必须有权访问受约束元素以验证约束。约束的所有者将决定何时评估约束。例如,操作 可以具有前置条件和/或后置条件约束。约束可以有一个可选名称,但通常是匿名的。约束根据以下语法显示为花括号中的文本字符串:
1 | constraint ::= '{' [ name ':' ] boolean-expression '}' |
OCL是 UML 中预定义的约束语言,但如果使用某些 UML 工具来绘制图表,则可以应用该工具支持的任何约束语言。对于符号为文本字符串(例如类属性)的元素,约束字符串属性后的花括号中定义。
对于应用于单个元素(例如类 或关联路径)的约束,约束字符串可以放置在元素的符号附近,最好靠近名称(如果有)。UML 工具必须能够确定受约束的元素。对于应用于两个元素(例如两个类或两个关联)的约束,该约束可以显示为大括号中的约束字符串标记的元素之间的 虚线。
约束字符串可以放置在注释符号中(与注释所用的相同),并通过虚线附加到受约束元素。
UML关联
关联是分类器之间的一种关系 ,用于表明分类器的实例可以相互链接,也可以在逻辑上或物理上合并成某种聚合。UML规范将关联归类为语义关系。其他一些 UML源也将关联归类为结构关系。关联 可以用于不同类型的 UML 结构图:
- 类图关联
- 用例图关联
- 部署图构件关联
- 部署图通信路径。
与关联相关的有几个概念:
- 关联最终所有权
- 导航性
- 关联性
- 聚合类型
二元关联关联两个类型实例。它通常呈现为连接两个分类器的实线,或将单个分类器连接到其自身的实线(两端是不同的)。该线可以由一个或多个连接的线段组成。链接是关联的一个实例。它是一个元组,关联的每一端都有一个值,其中每个值都是该端类型的实例。关联至少有两个末端,由属性(末端属性)表示。链接使用与关联相同的符号来呈现。实线连接实例 而不是分类器。链接名称可以显示为下划线,但这不是必需的。可以显示 结束名称(角色)和导航箭头。
UML泛化
泛化是 更一般的 分类器(超类)和更具体的分类器(子类) 之间的二元分类(即与分类相关) 定向关系。特定分类器的每个实例也是通用分类器的间接实例,因此我们可以说“患者是一个人”,“储蓄帐户是一个帐户”等。正因为如此,泛化关系也被非正式地称为“是”一种“关系”。泛化归特定分类器所有。括显示为一条线,在表示所涉及分类器的符号之间带有空心三角形作为箭头。箭头指向代表通用分类器的符号。这种表示法称为“单独目标样式”。
UML依赖
依赖性是一种有向关系 ,用于表明某个 UML 元素或一组元素需要、需要或依赖于其他模型元素来进行规范或实现。因此,依赖性被称为供应商-客户关系,其中供应商向客户提供某些东西,因此客户在某种意义上是不完整的,同时在语义或结构上依赖于供应商元素。供应商的修改可能会影响客户元素。依赖关系是命名元素 之间的关系 ,在 UML 中包括许多不同的元素,例如 类、 接口、 组件、 构件、 包等。下图显示了几种依赖关系。
Usage是一种依赖关系,其中一个命名元素 (客户端)需要另一个命名元素(供应商)来完成其完整定义或实现。Abstraction涉及代表相同概念但处于不同抽象级别的两个元素 。Deployment是一种依赖关系, 它显示工件到部署目标的分配。
依赖项通常显示为虚线箭头,从尾部的客户端(依赖项)指向箭头处的供应商(提供者)。箭头可以标有可选的构造型和可选的名称。因为箭头的方向与我们通常期望的方向相反,所以我通常将其定型为客户“依赖于”供应商。可以为客户或供应商提供一组元素。在这种情况下,一个或多个尾部位于客户端的箭头连接到一个或多个头部位于供应商的箭头的尾部。如果需要,可以在连接处放置一个小点。应在连接点附上有关依赖性的注释。
Required interface的接口指定分类器执行其功能并履行其对客户端的义务所需的服务。它由分类器和相应接口之间的使用依赖关系来指定。从分类器到接口的使用依赖性通过用半圆或插座表示接口来显示,用接口名称标记,用实线连接到需要该接口的分类器。
如果接口使用矩形表示法表示,则接口使用 依赖关系用依赖箭头表示。箭头尾部的分类器 使用(需要)箭头头部的接口。
UML嵌套分类器
UML中的类或接口可以用作其他分类器的命名空间。这种分类器的嵌套将类或接口中定义的分类器的可见性限制在命名空间的范围内。
嵌套分类器是在类或接口(的命名空间)内定义的分类器。请注意,UML 2.x 规范使用“定义于”、“嵌套于”和“拥有于”作为同义词,这会导致一些混乱。命名空间和嵌套分类器之间的关系称为命名空间所有权。
UML类图示例 - 图书馆领域模型
图书馆域模型描述了可在分析阶段使用的主要类和关系,以更好地理解集成图书馆系统(ILS)(也称为 图书馆管理系统(LMS) 的域区域。每个实体图书馆的物品——书籍、磁带、CD、DVD 等都可以有自己的物品编号。为了支持它,物品可能带有条形码。条形码的目的是提供唯一且可扫描的标识符,将条形码物理项目链接到目录中的电子记录。条形码必须物理附加到物品上,并且条形码编号输入到电子物品记录中的相应字段中。图书馆物品上的条形码可以被RFID标签取代。RFID标签可以包含物品的标识符、标题、材料类型等。它由RFID阅读器读取,无需打开书本封面或CD/DVD盒用条形码阅读器扫描。
图书馆图书属性ISBN和主题 继承自Book,并以前置 插入符号“^”显示。title属性显式地 重新定义 name。虽然属性的类型相同,但名称不同。lang属性被显式地重新定义为不同的类型。原始类型是自由文本字符串,而重新定义的属性是更具体(例如枚举)的语言类。在这种情况下,我们使用显式重定义,因为属性类型String和Language不相关。语言是 枚举类型。图书馆对于哪些内容可以借阅以及哪些内容仅供参考有一些规定。还规定了顾客可以借阅多少本书以及可以保留多少本书的规则。图书馆图书属性loanPeriod、dueDate和isOverdue是派生的。图书馆图书的借阅期限(借阅期限)取决于图书馆政策,并根据图书种类和借阅者的不同而有所不同。例如,在大学图书馆,本科生可以借书 30 天,研究生可以借书一个季度,教职员工可以借书一年。在公共图书馆,一本书的正常借阅期限可能是 3 周,而新书的借阅期限可能会缩短至 2 周。还书到期日根据借阅日期和借阅期限计算。如果截止日期超过当前日期,则默认为 false 的 isOverdue布尔值将设置为true。图书馆目录为图书馆顾客和工作人员提供有关图书馆馆藏的所有信息源的访问权限,允许按特定作者、特定主题或图书馆拥有的特定格式进行搜索。它告诉用户在哪里可以找到满足其特定需求的材料。
UML类图示例 - 网上购物领域模型
这里我们提供了一个UML类图的示例 ,它显示了在线购物的域模型。该图的目的是介绍网上购物的一些常用术语“词典” —— 客户、网络用户、帐户、购物车、产品、订单、付款等以及之间的关系。它可以用作业务分析师和软件开发人员之间的沟通。每个客户都有唯一的ID,并且与一个帐户 相关联。帐户拥有购物车和订单。客户可以注册为网络用户,以便能够在线购买商品。客户可以没有网络用户,因为也可以通过电话或从目录订购进行购买。Web用户具有登录名,该登录名也用作唯一 ID。Web用户可能处于多种状态 - 新的、活跃的、临时停用的或被禁止的,并且链接到购物车。购物车属于帐户。
账户拥有客户订单。客户可能没有订单。客户订单已排序且唯一。每个订单可能涉及多笔付款,也可能没有。每笔付款都有唯一的ID,并且与一个帐户相关。每个订单都有当前订单状态。订单和购物车都有关联到特定产品项目。每个产品项目都归属于一种产品。一个产品可以与许多产品项目相关联,也可以没有任何产品项目关联。
UML类图示例 - 银行帐户类图
这是一个使用UML泛化集描述某些类型的银行账户的示例。银行账户可以根据不同的标准分为UML泛化集。下面的示例图显示了按负债类型和账户类型划分的银行账户。这两个正交维度也有相应的类型—— LiabilityType和AccountType。银行账户可用于个人或商业目的。为了表明它假设完全覆盖并且不存在重叠,我们将责任类型约束显示为{complete, disjoint}。请注意,企业主仍然可以将个人银行账户用于其商业目的,但不建议这样做,主要是因为这会影响企业主的法律责任。从银行的角度来看,例如在开户时,这两个是两种不同的账户。银行账户的另一种分类是基于相关选项和功能,如下所示为账户类型概括集。为了表明该集合不完整但仍然没有重叠,我们将帐户类型约束显示为{incomplete, disjoint}。请注意,银行账户可以具有不同的账户负债和账户类型组合,例如个人储蓄账户或商业货币市场账户。
savings account(储蓄账户):目的是让我们存钱。账户持有人每月可以进行一定数量的存款和取款,而账户不提供支票。银行通常支付的利率高于支票账户,但低于货币市场账户或存款证。
checking account(支票账户):是一种银行账户,它使用支票作为从账户中提取或转账资金的方式 - 支付账单、购买物品、转账或贷款。通常银行允许账户持有人通过自动柜员机(ATM)进行取款和存款。 基本支票账户(有时称为简单账户)提供有限的服务。他们通常不支付利息,要求的最低余额较低,可能会限制每月开具和/或存入超过一定数量的支票。 有息支票账户的最低余额要求较高,但要支付利息(基于维持的平均余额),并且通常提供更好的服务,例如允许开立无限数量的支票。这些账户有时被称为可转让提款指令 (`NOW``) 账户。
Money market account(货币市场账户,MMDA):支付的利息高于储蓄或支票账户的利息。与支票或储蓄账户相比,货币市场账户通常需要更高的最低余额才能开始赚取利息。每月允许提取的资金非常有限。
Certificates of deposit account(定期存款账户):是一种银行账户,要求账户持有人存入相对较大的存款,并将资金在账户中保留一段约定的时间,通常是几个月或几年。提前提取资金会受到处罚。由于这些限制,定期存款账户支付的利息通常高于其他类型银行账户支付的利息。
此UML图上显示的两个特殊情况是儿童储蓄账户(Children’s Savings Account)和健康储蓄账户(Health Savings Account)(HSA)。这两个账户都是个人账户(Personal Account)和储蓄账户。它表现为多重继承。儿童储蓄账户是一种个人储蓄账户,可让儿童了解储蓄、利率并了解这对他们的储蓄意味着什么。有些银行要求一些月费或最低余额,如果账户不活跃或小额存款过多,可能会收取费用。健康储蓄账户(HSA)是个人储蓄账户,允许高免赔额健康计划承保的个人获得, 为未来医疗费用储蓄的税收优惠待遇。企业账户(Bussiness Account):主要对公的账户。
UML类图示例 Android相机实现类图
此示例是实现类图,其中显示了一些使用Android Camera API的类。API的详细信息可以在Android硬件Camera类中找到。使用Android相机 API中描述了我们遵循的示例实现。CameraDemo扩展了Android的Activity。Activity是用户可以使用Android执行的单一、集中的操作。Activity通常与用户交互,Activity类负责创建一个窗口,我们可以在其中放置用户界面。CameraDemo将创建一个Preview对象并保存对其的引用。Preview保留对Activity的引用作为其Context。Preview对象将创建一个Camera对象并将其返回CameraDemo的Activity。Camera类是Android硬件类,用于获取/创建Camera类的对象、设置图像捕获设置、开始或停止预览、拍照等。Camera类不是线程安全的,应从单个事件线程使用。此类是相机服务的客户端,它管理实际的相机硬件。
我们需要注册一些回调方法,以便在调用takePicture方法、打开快门、拍照以及图片数据准备好后,由Camera异步调用。SurfaceHolder是由持有显示表面的对象实现的接口。它允许我们控制表面大小和格式、编辑表面中的像素、监视表面的更改、直接访问表面对象等。SurfaceHolder.Callback接口允许接收有关表面更改的信息。
状态机图(State Machine Diagram)
状态机图是通过有限状态转换来设计系统的行为图。状态机图也可以用来表达系统的一部分使用协议。它可以分为行为状态机和协议状态机。
行为状态机
行为状态机试行为的专门化,用于通过有限状态转换来指定设计系统的一部分的离散行为。行为被建模为转换状态连接节点图的遍历。转换是由一系列事件的调度触发的。在遍历过程中,状态机还可以执行一些操作。行为状态机可以由行为分类器拥有 ,称为其上下文。上下文定义为此状态机有哪些信号、调用触发器以及哪些属性和操作在状态机的活动中可用。状态机的信号触发和调用触发是根据该分类器的接收方和操作来定义的。状态机可以具有相关联的 行为特征并且是该行为特征的方法。在这种情况下,状态机指定该行为特征的行为。状态机的参数与行为特征的参数相匹配,并提供用于访问状态机内的行为特征参数的方法。状态机的事件池是根据行为上下文分类器的实例的事件池,或者是拥有状态机作为方法的行为特征的分类器。状态机与其上下文分类器或行为特征之间的关联没有特殊的符号。
顶点被命名为元素,它是状态机图中节点的抽象。一般来说,它可以是任意数量的转换的源或目的地。顶点的子类有:状态,伪状态。状态是一个顶点 ,它模拟某种(通常是隐式的)不变量条件成立的情况。行为状态机 中的状态 模拟某种(通常是隐式的)不变量条件成立的情况。不变量可以表示静态情况,例如等待某些外部事件发生的对象。然而,它也可以对动态条件进行建模,例如执行某些行为的过程(即,所考虑的模型元素在行为开始时进入该状态,并在行为完成后立即离开该状态)。继承状态用虚线或灰色线绘制。包含以下几种状态:简单状态、复合状态、子状态。
简单状态是没有子状态的状态——它没有区域 并且没有子状态。状态可以将状态名称放置在附加名称选项卡内。名称选项卡是一个矩形,通常位于状态顶部的外侧。名称区以字符串形式保存状态的(可选)名称。没有名称的状态称为匿名状态,并且都被视为不同的(不同的)状态。如果使用名称选项卡,则不应使用名称隔间,反之亦然。建议不要在同一个图中多次使用同名的状态。内部活动隔间保存元素处于状态时执行的内部操作或状态(do)活动(行为)的列表。活动标签标识了将调用活动表达式指定的行为的情况。行为表达式可以使用所属实体范围内的任何属性和关联端。对于表达式为空的列表项,斜杠分隔符是可选的。内部转换隔间包含内部转换列表,其中每个项目都具有触发器所述的形式。如果防护条件不同,每个事件名称可能会在每个状态中出现多次。事件参数和保护条件是可选的。如果事件有参数,则可以通过当前事件变量在表达式中使用它们。
复合状态被定义为具有子状态(嵌套状态)的状态。子状态可以是顺序的(不相交的)或并发的(正交的)。UML 2.4 将复合状态定义为包含一个或多个区域的状态 。(请注意,该区域被定义为复合状态或状态机的正交部分。)状态不允许同时具有区域和子机。简单复合状态仅包含一个区域。正交复合态具有多个区域。每个区域都有一组互斥的不相交子顶点和一组过渡。给定状态只能用这两种方式之一来分解。
复合状态的每个区域可以具有初始伪状态和最终状态。到封闭状态的转变表示到每个区域中的初始伪状态的转变。新创建的对象采用其最顶层的默认转换,该转换源自每个区域的最顶层初始伪状态。复合状态可能会将状态名称放置在附加名称选项卡内。名称选项卡是一个矩形,通常位于状态顶部的外侧。复合状态可能有隔室。状态的划分是:名称隔间、内部活动隔间、内部转换隔间、分解室。复合状态可以 在其外部边界上或紧邻该边界(内部或外部) 具有一个或多个入口点和出口点。
最终状态是一种特殊的 状态 ,表示封闭区域已完成。如果封闭区域直接包含在状态机中,并且状态机中的所有其他区域也完成,则意味着整个状态机完成。
协议状态机
UML协议状态机图用于表达使用协议或 某些分类器的生命周期。它显示了在分类器的每个状态下可以调用分类器的哪些操作,在哪些特定条件下,以及在分类器转换到目标状态后满足一些可选的后置条件。由于这些图显示了生命周期,因此它们可用于显示可能存在一段时间的一类对象的不同稳定状态,并解释对象如何随时间改变其状态。例如,我们可以展示如何创建、激活、暂停和取消用户帐户。协议状态机图的主要元素是 协议状态、 协议转换和不同的伪状态,如下面的概述图所示。
协议状态机是行为状态机的特化 ,用于表达使用协议或分类器 的生命周期。它指定了在什么状态和什么条件下可以调用分类器的哪些操作,从而指定了分类器操作上允许的调用顺序。协议状态机表示分类器可以触发的合法转换。协议状态机始终在分类器的上下文 中定义。一个分类器可以有多个协议状态机。协议状态机的所有转换都必须是 协议转换。协议状态机的表示法与行为状态机的表示法类似。关键字{protocol}放置在状态机名称附近,以区分协议状态机图。
协议状态机的状态(协议状态)呈现了向其客户端公开的类的外部视图。根据上下文,协议状态可以对应于行为状态机表示的实例的内部状态,也可以不同。协议状态机的状态暴露给其上下文分类器的用户。协议状态代表其上下文分类器的公开稳定情况:当分类器的实例不处理任何操作时,该实例的用户始终可以知道其状态配置。协议状态机的状态不能有进入、退出或执行活动操作。协议状态机也不能有深或浅的历史伪状态。协议状态机可以具有子状态机状态、复合状态和并发区域。
例如,并发区域可以表达一个实例可以同时具有多个活动状态的协议。子状态机和复合转换与行为状态机一样用于分解复杂的协议状态机。协议转换是 用于协议状态机的(行为)转换的专业化 ,它指定操作的合法转换。协议转换具有以下特征:前置条件(保护)、触发器和后置条件。协议转换通常与属于协议状态机的上下文分类器的某些操作相关联。协议转换指定可以在初始条件(保护)下为原始状态中的实例调用关联(引用)操作,并且在转换结束时,将在满足后置条件的情况下到达目标状态。复合转换也可用于协议状态机。协议转换呈现为从源顶点 到目标顶点的转换箭头,并带有描述转换的可选文本。
协议转换的文本符号由以下语法规则描述:
1 | protocol-transition ::= [ pre-condition ] trigger '/' [ post-condition ] |
协议转换的行为转换的保护称为pre-condition,并放置在触发器之前。后置条件已添加到协议转换中并出现在触发器之后。协议转换没有behavior-expression。目前尚不清楚 触发对于协议转换是否是可选的,因为它对于行为转换是可选的。协议转换语法和示例都在触发器后显示“/”,这与行为转换不同,其中“/”是放置在behavior-expression之前的标记。其他一切都是“通常的状态机符号”。
UML 状态机图-水状态机图示例
水可以有多重状态 —— 液体、气体、固体和等离子体。从一种状态转换到另一种状态是可以的。例如,固态是从液态到冰的相变。冷凝是从气态到液态的相变。水蒸气可以通过沉积直接变成霜。
UML 状态机图-银行ATM行为状态机图示例
这是UML行为状态机图的示例 ,显示了银行自动柜员机 (ATM) 顶级状态机。ATM最初是关闭状态。电源接通后,ATM执行启动动作,进入自检状态。如果测试失败,ATM将进入“停止服务”状态,否则将无触发地转换到“空闲”状态。在此状态下,ATM等待客户交互。当客户将银行卡或信用卡插入ATM读卡器时, ATM状态将从“空闲”更改为“服务客户” 。进入服务客户状态后,执行进入操作 readCard。请注意,从服务客户状态返回空闲状态的转换可以由取消事件触发,因为客户可以随时取消交易。
服务客户状态是一个复合状态 ,按子状态的顺序有:“客户身份验证”、“选择事务” 和“事务”。 客户身份验证和交易本身就是复合状态,以隐藏的分解指示器图标显示。 交易完成后,服务客户状态会无触发地转换回空闲状态。该状态还具有退出操作jectCard,该操作在离开该状态时释放客户的卡,无论是什么导致了该状态的转换。
UML 状态机图-网上购物状态机图示例
这里我们提供一个在线购物背景下的用户帐户生命周期的示例,如UML协议状态机图所示。对于要创建的用户帐户,它必须满足一些初始要求。例如,用户ID(用作登录名)必须是唯一的,至少对于现有帐户而言是如此。创建帐户后,可能需要对其进行验证。验证取决于公司,可能包括电子邮件、电话和地址验证。如果帐户在某个预定义的时间段内未得到验证,则该帐户可能会被移至暂停帐户。
新的、活跃的或暂停的帐户可以根据客户的要求随时取消。请注意,这样做的先决条件通常包括支付任何未结余额,并且可能需要一些单独的帐户状态或子状态来处理这种情况。出于安全原因,用户帐户可能会被手动或自动暂停。例如,如果使用不正确的帐户密码多次尝试登录失败,网站入侵检测系统会在预定义的时间内锁定用户帐户。账户锁定超时后,账户自动恢复激活。某些用户帐户可能会长时间处于非活动状态。公司政策或业务规则可能要求将此类休眠帐户一两年转为暂停状态。一旦我们列出了用户帐户状态并指定了从一种状态到另一种状态的所有可能转换,我们就可以与其他业务专家一起查看该图表,看看是否有任何遗漏或需要进一步澄清。
UML 状态图是图表本身的名称,主要用于描述对象具有的各种状态、状态之间的转换过程以及触发状态转换的各种事件和条件。UML 状态图描述了一个状态机,可以被定义为一台机器,它定义了一个对象,这些状态控制外部或内部事件的不同状态,状态机由状态、转换、事件、活动和动作五部分组成。
- 状态:状态指的是对象在其生命周期中的一种状况,处于某个特定状态中的对象必然会满足某些条件、执行某些动作或者是等待某些事件。一个状态的生命周期是一个有限的时间阶段;
- 转换:转换指的是两个不同状态之间的一种关系,表明对象在第一个状态中执行一定的动作,并且在满足某个特定条件下由某个事件触发进入第二个状态;
- 事件:事件指的是发生在时间和空间上的对状态机来讲有意义的那些事情。事件通常会引起状态的变迁,促使状态机从一种状态切换到另一种状态,如信号、定时器,某个条件被处罚等;
- 活动:活动指的是状态机中进行的非原子操作;
- 动作:动作指的是状态机中可以执行的哪些原子操作。所谓原子操作,指的是他们在运行的过程中不能被其他消息中断,必须一直执行下去,以至最终导致状态的变更或者返回一个值;
一个状态图(Statechart Diagram)本质上就是一个状态机,或者是状态机的特殊情况,它基本上是一个状态机中元素的一个投影,这也就意味着状态图包括状态机的所有特征。
状态图描述了一个实体基于事件反映的动态行为,显示了该实体是如何根据当前所处的状态对不同的事件作出反应的。
在UML中,状态图由表示状态的节点和表示状态之间转换的带箭头的直线组成。状态的转换由事件触发,状态和状态之间由转换箭头连接。每一个状态图都有一个初始状态(实心圆),用来表示状态机的开始。还有一个中止状态(半实心圆),用来表示状态机的终止。状态图主要由元素状态、转换、初始状态、中止状态和判定等组成。
状态
状态用于对实体在其生命周期中的各种状况进行建模,一个实体总是在有限的一段时间内保持一个状态。状态由一个带圆角的矩形表示,状态的描绘素应该包括名称、入口和出口动作、内部转换和嵌套状态。如下图,为一个简单状态:
- 状态名指的是状态的名字,通常用字符串表示,其中每个单词的首字母大写。状态名可以包含任意数量的字母、数字和除了冒号“:”以外的一些字符,可以较长,甚至连续几行。但是一定要注意一个状态的名称在状态图所在的上下文中应该是唯一的,能够把该状态和其他状态区分开。
- 入口和出口动作一个状态可以具有或者没有入口和出口动作。入口和出口动作分别指的是进入和退出一个状态时所执行的“边界”动作。
- 内部转换指的是不导致状态改变的转换。内部转换中可以包含进入或者退出该状态应该执行的活动或动作。
- 嵌套状态状态分为简单状态(Simple State)和组成状态(Composite State)。简单状态是指在语义上不可分解的、对象保持一定属性值的状况,简单状态不包含其他状态:而组成状态是指内部嵌套有子状态的状态,在组成状态的嵌套状态图部分包含的就是此状态的子状态。
转换
在UML的状态建模机制中,转换用带箭头的直线表示,一端连接源状态,箭头指向目标状态。转换还可以标注与此转换相关的选项,如事件、监护条件和动作等,如下图所示。注意:如果转换上没有标注触发转换的事件,则表示此转换自动进行。
在状态转换机制中需要注意的五个概念如下:
- 状态源(Source State):指的是激活转换之间对象处于的状态。如果一个一个状态处于源状态,当它接收到转换的触发事件或满足监护条件时,就激活了一个离开的转换。
- 目标状态(Event State):指的是转换完成后对象所处的状态。
- 事件触发器(Event Trigger):指的是引起源状态转换的事件。事件不是持续发生的,它只发生在时间的一点上,对象接收到事件,导致源状态发生变化,激活转换并使监护条件得到满足。
- 监护条件(Guard Condition):是一个布尔表达式。当接收到触发事件要触发转换时,要对该表达式求值。如果表达式为真,则激活转换:如果表达式为假,则不激活转换,所接收到的触发事件丢失。
- 动作(Action):是一个可执行的原子计算。
初始状态
每个状态图都应该有一个初始状态,它代表状态图的起始位置。初始状态是一个伪状态(一个和普通状态有连接的假状态),对象不可能保持在初始状态,必须要有一个输出的无触发转换(没有事件触发器的转换)。通常初始状态上的转换是无监护条件的,并且初始状态只能作为转换的源,而不能作为转换的目标。在UML中,一个状态图只能有一个初始状态,用一个实心圆表示。
终止状态
终止状态是一个状态图的终点,一个状态图可以拥有一个或者多个终止状态。对象可以保持在终止状态,但是终止状态不可能有任何形式的和触发转换,它的目的就是为了激发封装状态上的转换过程的结束。因此,终止状态只能作为转换的目标而不能作为转换的源,在UML中,终止状态用一个含有实心圆的空心圆表示。
判定
活动图和状态图中都有需要根据给定条件进行判断,然后根据不同的判断结果进行不同转换的情况。实际就是工作流在此处按监护条件的取值发生分支,在UML中,判定用空心菱形表示。
序列图(Sequence Diagram)
序列图也叫时序图,是交互图的一种,用于捕获系统运行中对象之间有时间顺序的交互,是由生命线、执行、消息、交互、组合片段组成。时序图将交互关系表示为一个二维图。纵向是时间轴,时间沿竖线向下延伸。横向轴代表了在协作中各独立对象的类元角色。类元角色用生命线表示。当对象存在时,角色用一条虚线表示,当对象的过程处于激活状态时,生命线是一个双道线。消息用从一个对象的生命线到另一个对象生命线的箭头表示。箭头以时间顺序在图中从上到下排列。
Actor(角色:代表某个由人或者设备扮演的角色,它不一定代表某个具体的实体,一般由一个小人代替;
Lifetime(生命线):在时序图中表示为从对象图标向下延伸的一条虚线,表示对象存在的时间。
Activation(活动条/激活):在生命线的徐线上可以用活动条表示某种行为的开始和结束,一般用小矩形来表示。
同步消息:意味着阻塞和等待。如:A向B 发送一个消息后,对象A 必须一直等到B执行完成后返回才能继续往下执行。这就是同步消息。用实心箭头表示
异步消息:就意味着是非阻塞。如:A向B发送消息后,直接可以执行下面代码,无需等待B的执行。
执行事件:执行事件是表示动作或行为开始或结束时刻的事件。
状态恒等式:状态不变量是一个交互片段 ,它表示 交互参与者的运行时约束。它可用于指定不同类型的约束,例如属性或变量的值、内部或外部状态等。在执行下一个发生规范之前立即评估约束,以便已执行所有未显式建模的操作。如果约束为真,则该迹线是有效迹线,否则该迹线是无效迹线。状态不变量通常显示为生命线上花括号中的约束。
交互片段:允许使用(或调用)另一个交互。大型且复杂的序列图可以通过交互使用来简化。交互使用的语法为:
1
2
3interaction-use ::= [ attribute-name '=' ] [ collaboration-use '.' ] interaction-name [ io-arguments ] [ ':' return-value ]
io-arguments ::= '(' io-argument [ ',' io-argument ]* ')'
io-argument ::= in-argument | 'out' out-argument属性名称指的是交互中将接收交互结果的生命线之一的属性。请注意,这限制了交互结果仅分配给属性。在现实生活中,方法调用的结果可以分配给调用方法的变量。
io-arguments是 交互的输入或输出参数的列表。返回消息:在从A发送消息到达B之后,B的回复消息称之为返回消息。
交互
交互是行为和交互片段的特化,交互片段表示关注可连接元素之间可观察的信息交换的行为单元。交互是一种突发行为。交互的重点是在分类器的可连接元素之间通过消息传递信息。
交互的语义在UML中定义为一对跟踪集——有效跟踪和无效跟踪。不包含在这两个集合中的踪迹不被交互描述,并且不知道它们是有效还是无效。跟踪是表示为<e1, e2, ... , en>的事件发生序列,其中每个事件都由事件规范进行描述。交互中的每次出现通常被解释为花费为零。始终假定持续时间是在事件之间进行测量的。作为一种行为,交互是可专门化和可重新定义的。专门化交互只允许在原始交互的基础上添加更多痕迹。由专业化定义的跟踪与联合的继承交互的跟踪相结合。拥有交互的分类器可以是专门化的,并且在专门化中可以重新定义交互。重新定义交互意味着将重新定义的交互替换为重新定义的交互。交互的符号是实心矩形框架。矩形左上角的五边形包含关键字sd,后跟交互名称和参数。它使用行为名称的一般符号。矩形框内的符号是以下形式之一: 序列图、 通信图、 时序图或 交互概述图。
组合片段
| 符号 | 图 | 描述 |
|---|---|---|
| alt - alternatives | ![]() |
交互运算符alt表示组合片段代表行为的选择或替代。最多会选择一个操作。所选操作必须具有显式或隐式保护表达式,在交互中该表达式的计算结果为true。 |
| opt - option | ![]() |
交互运算符opt表示组合片段代表一种行为选择,其中(唯一)操作数发生或什么都不发生。选项在语义上等同于替代组合片段,其中一个操作数具有非空内容,第二个操作数为空。 |
| loop - iteration | ![]() |
如果指定了两个边界,则循环将迭代最少min-int次数,最多迭代max-int次数。除了迭代边界之外,循环还可以具有交互约束, 方括号中的布尔表达式。 |
| break - break | ![]() |
交互操作符break表示执行的中断或异常场景,而不是封闭交互片段的其余部分。请注意,UML只允许放弃一层(直接封闭交互片段)。 |
| par - parallel | ![]() |
交互运算符par定义了组合片段的操作数的行为的潜在并行执行。不同的操作数可以以任何方式交错,只要保留每个操作数施加的顺序即可。 |
| strict - strict sequencing | ![]() |
交互运算符strict要求在组合片段内的第一级上对操作数进行严格排序(顺序)。 |
| seq - weak sequencing | ![]() |
弱测序seq由具有以下属性的跟踪集定义:1.每个操作数中出现规范的顺序都保留在结果中。2. 来自不同操作数的不同生命线的出现规范可以按任意顺序出现。3. 来自不同操作数的同一生命线上的出现规范被排序,使得第一操作数的出现规范出现在第二操作数的出现规范之前。因此,当操作数位于不相干的参与者集上时,弱排序seq会简化为并行合并。当操作数仅作用于一名参与者时, 弱排序会降低为严格排序。 |
| critical - critical region | ![]() |
交互操作符Critical定义了组合片段代表一个关键区域。关键区域是具有不能与其他发生规范交错的痕迹的区域(在该区域覆盖的生命线上)。这意味着该区域 由封闭片段以原子方式处理,并且不能被交错,例如通过并行运算符。 |
| ignore - ignore | ![]() |
交互运算符忽略意味着有一些消息未在此组合片段中显示。这些消息类型可以被认为是无关紧要的,并且如果它们出现在相应的执行中,则被隐式忽略。 |
| consider - consider | ![]() |
交互运算符考虑定义了在此组合片段中应考虑哪些消息,这意味着任何其他消息都将被忽略。所考虑的消息列表位于一对花括号“{”和“}”中括起来的操作数之后。考虑操作通常与其他操作结合使用,例如“断言考虑{m,s}”。 |
| assert - assertion | ![]() |
交互运算符断言表示断言,即断言操作数的序列是唯一有效的延续(必须通过系统的正确设计来满足)。所有其他延续都会导致无效跟踪。 |
| neg - negative | ![]() |
交互运算符neg描述了被定义为负(无效)的跟踪组合片段。是系统出现故障时出现的痕迹。所有不同于消极的交互片段都被认为是积极的,这意味着它们描述了有效且应该是可能的痕迹。 |
举几个示例:
UML 序列图-Facebook网络用户身份验证序列图示例
UML序列图 示例 ,显示如何在Web应用程序中对Facebook (FB)用户进行身份验证,以允许访问他/她的FB资源。Facebook使用OAuth 2.0协议框架,该框架使Web应用程序(称为“客户端”)(通常不是FB资源所有者,而是代表FB用户)请求访问由FB用户控制并由FB服务器托管的资源。Web应用程序获取访问令牌,而不是使用FB用户凭据来访问受保护的资源。Web应用程序应由Facebook注册以拥有应用程序ID(client_id)和密钥 (client_secret)。当收到对某些受保护Facebook资源的请求时,Web浏览器(“用户代理”)将被重定向到 Facebook的授权服务器,其中包含应用程序ID以及授权过程后用户应重定向回的URL。用户收到返回的许可请求表。如果用户授权应用程序获取他/她的数据,Facebook授权服务器将重定向回之前指定的URI以及授权代码(“验证字符串”)。Web应用程序可以将授权代码交换为OAuth访问令牌。
如果Web应用程序获取FB用户的访问令牌,它可以通过在Facebook Graph API请求中包含访问令牌来代表该FB用户执行授权请求。如果用户未授权Web应用程序,Facebook会向之前指定的URI发出重定向请求,并添加error_reason参数以通知Web应用程序授权请求被拒绝。
活动图(Activity Diagram)
活动图是UML行为图,它显示控制流或对象流,重点是流的顺序和触发条件。由活动模型可以协助其他操作完成执行、因为对象、数据或者因为流外部的某些事件触发而被启动。UML活动图通常绘制以下节点和边:活动、分区、操作、对象、控制、活动边。
活动
活动是一种参数化的”行为“,表示为协调的动作流。执行流程 被建模为由活动边连接的活动节点。节点可以是从属行为的执行,例如算术计算、对操作的调用或对象内容的操作。活动节点还包括控制结构流,例如同步、决策和并发控制。活动可以形成调用其他活动的调用层次结构,最终解决单个操作。在面向对象的模型中,活动通常作为绑定到直接调用的操作的方法来间接调用。活动包含活动节点,活动节点有:action、object、control。活动可能包含各种类型的 操作:
- 原始函数,例如:算数函数。
- 行为的调用,例如:活动。
- 通信事件,例如:发送信号。
- 操作对象,例如:读取和写入对象属性的值。
有些操作会调用活动 - 直接call behavior action或间接call operation action。活动可以呈现为圆角矩形,活动名称位于左上角,活动的节点和边缘位于边框内。UML2.4规范示例以粗体显示活动名称。
活动参数显示在边框上并在活动名称下方列出,如下所示:parameter-name: parameter-type。
作为行为 活动可能有前置条件和后置条件约束。如果存在,则分别用关键字“前置条件”和“后置条件”显示。关键字“singleExecution”用于作为单个共享执行(单例)的活动,否则每个调用都在其自己的空间中执行。圆角活动边框可以用图表的框架符号代替。在这种情况下,框架的类型是活动或简称行为。活动参数(如果有)显示在框架上。
带有关键字“activity”的类表示法可用于显示反射活动的特征,以表明它是一个活动类。必要时也可以使用关联和状态机符号。UML允许行为产生标记,这些标记是活动,并且可以在运行时执行。
分区
分区是某些具有共同特征的操作的活动组。分区通常对应于业务模型中的组织单位或业务参与者。分区提供了活动中调用的行为的受限视图。可以根据分区所代表的元素的类型来选择约束。包括:分类器、实例、part、属性和值。例如,分区可以代表特定的分类器。在这种情况下,每个分区中的动作应该是针对作为相应分类器的实例的对象的操作或信号。分区可以表示某些属性及其子分区——该属性的特定值。例如,分区可以表示执行行为的位置,而子分区将表示该属性的特定值。分区可以使用泳道符号来显示 - 有两条平行的线,水平或垂直,以及一端在框中标记分区的名称。活动节点,例如放置在这些线之间的动作和边,都被认为包含在分区内。
分层分区使用子分区的泳道来表示,如下所示。
活动边
是定向连接的抽象类,令牌或数据对象沿着这些连接在活动节点之间流动 。它包括控制边和对象流边。边的源和目标必须与边处于同一活动中。活动边缘由连接两个活动节点的开放箭头线表示。边可以被命名,但是,边不需要在活动中具有唯一的名称。如果边有名称,则会在箭头附近注明。
活动边缘有一个guard,在运行时评估以确定是否可以遍历边缘。对于提供沿边缘传递的每个令牌,guard必须将其评估为真。活动边的guard显示在方括号中。
活动边可以使用连接器来表示,连接器是一个内部有名称的小圆圈。尽管UML2.4规范将其称为“边的名称”,但提供的连接器符号和示例表明连接器有自己的名称(也称为“标签”)。连接器通常用于避免绘制长边。这纯粹是符号性的。它不会影响底层模型。涉及的圆和线映射到模型中的单个活动边。每个具有给定标签的连接器都必须与同一活动图上具有相同标签的其他连接器完全配对。一个连接器必须恰好具有一个传入边,另一个连接器必须恰好具有一个传出边缘,每个连接器都具有相同类型的流、对象或控制。
对象流边
对象流边是活动边,用于显示操作节点之间的对象和数据令牌的数据流。对象流由带箭头的线表示。
任意数量的令牌都可以沿着边通过,可以一次成组,也可以在不同时间单独通过。权重属性规定了必须同时穿过边缘的最小令牌数量。当提供最小数量的令牌时,源处的所有令牌都会一次性提供给目标。边的权重可以显示在包含权重的花括号中。权重是一个值,它可以是一个常数,其计算结果为非零无限自然值。无限重量用“*”表示。
中断边
中断边是表示具有中断的区域的中断的活动边。它被渲染为一道闪电。
标记中断边的一个选项是在直线上使用之字形装饰。
Actions
Action是一个命名元素,它代表Activity中的单个原子步骤 ,即在Activity中不会进一步分解。 活动表示由单独的元素(即操作)组成的行为。请注意,调用行为操作可能引用(调用)活动。此操作对于包含它的活动来说很简单,但其效果可能很复杂。活动定义了可以在许多地方重用的行为。Action被标记为圆角矩形。 Action的名称或描述放置在矩形内部。Action的名称通常是动作的动词或名词,并带有一些解释。不要使用状态名称作为操作名称。Action也可以用一些依赖于应用程序的动作语言 来表达。Action可以具有指定来自和去往其他节点的 控制流和数据流的传入和传出活动边集。在满足所有输入条件之前,操作不会开始执行。动作执行的完成可以启用一组后继节点和动作的执行,这些后继节点和动作从该动作的输出获取它们的输入。如果某个动作执行过程中出现异常,则该动作的执行将被放弃,并且该动作不会生成常规输出。如果操作有异常处理程序,它将接收异常对象作为令牌。如果该操作没有异常处理程序,则异常会传播到封闭节点,依此类推,直到被其中之一捕获。如果异常从嵌套节点(操作、结构化活动节点或活动)传播出去,则嵌套节点中的所有标记都会终止。描述异常的数据表示为任何类的对象。本地前置条件和本地后置条件是分别在执行开始和完成时应保持的约束。它们仅保存在流程中指定的点,而不是全局保存在流程中其他位置或其他图表上的行为的其他调用。如何执行本地前置条件和后置条件由实现决定。例如,可以在编译时或运行时检测违规。效果可能是停止执行的错误或只是警告等等。本地前置条件和本地后置条件分别以关键字“localPrecondition”和“localPostcondition”附加到调用的注释的 形式显示 。
下面列出了操作子类:
| 符号 | 图 | 描述 |
|---|---|---|
| Object Action | 对象动作包括对对象的不同动作。对象操作在 UML 标准中并未明确出现,为了清楚起见,将其添加到此处。在 UML 标准中,所有对象操作都是 操作的直接子类。 | |
| Variable Action | ![]() |
|
| Invocation Action | ![]() |
|
| Call Behavior Action | ![]() ![]() |
Call behavior action是直接调用行为 而不是调用调用该行为的操作的调用动作。它显示为带有 由放置在操作的圆角矩形内的操作或行为描述执行的行为的名称的操作。如果节点名称与行为名称不同,则它会出现在符号中。请注意,因为它看起来与常见操作完全相同,所以仅看图无法判断该名称是常见操作名称、调用行为操作名称还是某些行为名称。Call activity action由操作符号内的耙式符号指示。 |
| Send Signal Action | ![]() |
Send signal action是一种调用操作,它从其输入创建信号,并将其传输到指定的目标对象,在该目标对象中可能会导致状态机转换的触发或活动的执行。当满足动作执行的所有先决条件时,从参数生成信号并将其传输到识别的目标对象。信号的发送者(也称为“请求者”)立即继续执行,而不等待任何响应。发送信号动作被标记为凸五边形。请注意,操作的名称与其发送的信号类的名称相对应 。 目标对象未使用此表示法指定。 |
| Structural Feature Action | ![]() |
|
| Link Action | ![]() |
|
| Event Action | ![]() |
|
| Accept Event Action | ![]() |
Accept event action用凹五边形表示。如果接受事件操作没有传入边,则该操作将在包含活动或结构化节点有传入边时启动,以最直接包含该操作的为准。此外,没有传入边沿的接受事件操作在接受事件后仍保持启用状态。它在接受事件并输出值后并不终止,而是继续等待其他事件。 |
| Accept Event Action with incoming edges | ![]() |
Accept event action可以有传入边缘。在这种情况下,该操作在前一个操作完成后开始。 |
| Wait Time Action | ![]() |
如果事件是时间事件发生,则结果值包含发生的时间。这种操作非正式地称为wait time action,用沙漏表示。 |
控件
控制节点是一个活动节点,用于协调其他节点之间的流量。包括:初始节点、流最终节点、活动最终节点、决策节点、合并节点、分叉节点、加入节点。
| 符号 | 图 | 描述 |
|---|---|---|
| Initial Node | ![]() |
初始节点是一个控制节点,当活动被调用时,流程从该节点开始。活动可能有多个初始节点。初始节点显示为小实心圆圈。 |
| Flow Final Node | ![]() |
流最终节点是终止流的控制最终节点。流程最终节点的符号是内部有X的小圆圈。 |
| Activity Final Node | ![]() |
活动最终节点是停止活动中所有流程的控制最终节点。Activity Final是UML 2.0中的新增功能。活动最终节点显示为实心圆,内部有空心圆。它可以被认为是一个被称为“靶心”或目标的目标。 |
| Decision Node | ![]() ![]() ![]() ![]() |
决策节点是一种控制节点,它接受一个或两个传入边上的令牌 ,并从一个或多个传出流中选择一个传出边。决策节点的符号是菱形符号。对于决策点,可以为最多一个传出边缘 定义预定义的保护“else”。决策可以有决策输入行为。UML中引入了决策输入行为,以避免警卫中的冗余重新计算。在这种情况下,每个数据令牌都会在传出边缘上评估防护之前传递给行为。行为的输出可供每个警卫使用。决策输入行为由关键字“decisionInput”指定,并且一些决策行为或条件放置在注释符号中,并附加到适当的决策节点。决策也可能有决策输入流。在这种情况下,在决策输入流上提供的令牌可供每个传出边缘上的警卫使用,确定常规传入边缘上的提议是否沿着该传出边缘传递。决策输入流由注释该流的关键字“decisionInputFlow”指定。 |
| Merge Node | ![]() |
合并节点是一个控制节点,它将多个传入备用流汇集在一起以接受单个传出流。没有令牌的加入。不应使用合并来同步并发流。合并节点的符号是一个菱形符号,有两条或多条边进入该节点,并且有一条活动边离开该节点。 |
| Merge and decision combined | ![]() |
合并节点和决策节点 的功能可以通过使用相同的节点符号来组合。 |
| Fork Node | ![]() |
分叉节点是一种控制节点,具有一个入边和多个出边,用于将传入流拆分为多个并发流。 分叉节点的表示法是一条线段,其中有一条活动边进入该线段,并且有两条或更多条边离开该线段。 |
| Join Node | ![]() ![]() |
Join节点是一个控制节点,具有多个入边和一个出边,用于同步传入并发流。连接节点的表示法是一条线段,其中有多个活动边进入其中,并且只有一条边离开它。连接规范显示在连接节点附近的大括号中,如joinSpec=...。 |
| Join and fork combined | ![]() |
连接节点和分叉节点 的功能可以通过使用相同的节点符号来组合。果在从分叉传出的边缘上使用防护,建模者应确保下游连接不依赖于通过受防护边缘的令牌的到达。如果这种情况无法避免,则应引入决策节点来进行防护,并在防护失败时将令牌分流到下游连接 |
| 符号 | 图 | 描述 |
|---|---|---|
| Object Nodes | ![]() ![]() |
对象节点是抽象活动节点,用于定义 活动中的对象流。对象节点包括 pin、 central buffer、 parameter、 expansion节点。它表示特定分类器的实例 (可能处于特定状态)可能在活动中的特定点可用。对象节点可以通过多种方式使用,具体取决于对象的流动方向和流动方向。对象节点被标记为矩形。标记节点的名称放置在符号内,其中名称指示对象节点的类型,或节点的名称和类型,格式为"name:type."。该名称还可以由一个或多个状态限定,该状态将写在类型名称下方的括号内。除默认值外的上限、排序和控制类型均在对象节点下方的大括号中注明。 |
| Pin | ![]() |
引脚是用于操作输入和 输出的对象节点。引脚通常显示为附加到操作矩形的小矩形。引脚名称可以显示在引脚附近。 |
| Data Store | ![]() |
数据存储 是非瞬态信息的 中央缓冲节点。数据存储用关键字“datastore”表示为对象节点。中央缓冲区 节点是 用于管理来自多个源和目的地的流的对象节点。中央缓冲节点接受来自流中多个对象的令牌,缓冲这些令牌并将它们传递到输出流。中央缓冲区不直接连接到操作。请注意,所有对象节点都具有内置的数据缓冲功能。 引脚 可以缓冲操作数据,而活动参数则用于活动。中央缓冲区的不同之处在于它不与动作或活动相关联。它为对象流之间的排队和竞争提供额外的支持。中央缓冲区被标记为带有可选关键字“centralBuffer”的对象节点,可以将其与独立引脚区分开来。 |
UML 活动图-网上购物活动图示例
在线购物活动图的示例 。在线客户可以浏览或搜索商品、查看特定商品、将其添加到购物车、查看和更新购物车、结账。用户可以随时查看购物车。假定结账包括用户注册和登录。此示例不使用分区,大部分操作均假设由在线客户完成。
UML 活动图-处理购物订单活动图示例
订单处理的业务流程活动示例,请求的订单是活动的输入参数。订单被接受并填写所有必需信息后,付款被接受并发货。请注意,此业务流程允许在发送发票或确认付款之前发货订单。
UML 活动图-文件管理流程活动图示例
描述文档管理流程的UML活动图示例。任何大公司通常都需要某种正式且适当文件管理流程,尤其是在遵守法规的情况下。文档会经历不同的状态或阶段 - 它被创建、审查、更新、批准,并在某个时刻存档。参与此过程的不同角色包括 作者、审阅者、批准者和所有者。这些角色在图表上通过 呈现为水平“泳道”的分区来表示。
该活动图显示了不同角色的职责以及文档更改的流程或顺序。 在这种情况下,也可以使用替代的图 - 状态机图来显示文档如何随时间改变其状态。请注意,Document对象并不是此活动图上显示的唯一对象节点。还有另一个对象 - Change Request,该对象用于将审阅者请求的文档更改传递给该对象。文档的状态图仅显示文档状态和转换,因此当涉及不同的角色和多个对象节点时,活动图非常有用。
UML 活动图-解决软件问题活动图示例
UML活动图示例,显示如何解决软件设计中的问题。在某个机构创建票证并重现问题后,确定问题,确定解决方案,修复并验证问题,如果问题得到解决,则关闭票证。此示例没有使用分区,因此不太清楚谁负责完成每个具体操作。
UML 活动图-Google Apps单点登录(SSO)活动图示例
为了与合作伙伴公司进行交互,Google使用基于OASIS SAML 2.0协议 的单点登录。Google充当服务提供商,提供Gmail或起始页等服务。合作伙伴公司充当身份提供商,控制用于识别、验证和授权用户使用Google托管的网络应用程序的用户名、密码和其他信息。每个合作伙伴都向Google提供其SSO服务的URL以及Google将用来验证SAML响应的公钥。
当用户尝试使用某些托管的Google应用程序(例如 Gmail)时,Google会生成SAML身份验证请求并将重定向请求发送回用户的浏览器。重定向指向特定的身份提供商。SAML身份验证请求包含用户尝试访问的Google应用程序的编码URL。合作伙伴身份提供商通过请求有效的登录凭据或检查其自己的有效身份验证cookie来对用户进行身份验证。合作伙伴生成SAML响应并对其进行数字签名。响应将转发至Google的断言消费者服务(ACS)。Google的ACS使用合作伙伴的公钥验证SAML响应。如果响应有效并且用户身份得到身份提供商的确认,ACS会将用户重定向到目标URL。否则用户将看到错误消息。
UML 活动图-Sentinel HASP SL-试用产品的激活活动图示例
该产品受Sentinel HASP软件保护和许可安全解决方案的Sentinel HASP SL软件密钥保护。Sentinel HASP可防止软件盗版和知识产权盗窃造成的损失。例如它为虚拟环境中的许可提供业界领先的支持,并且是市场上第一个支持J2EE应用程序的软件许可和逆向工程保护工具解决方案。Sentinel HASP软件包括Business Studio- 一款功能强大、基于角色的软件许可和管理工具。Business Studio产品、营销和开发人员使用,为市场准备软件产品,包括将应用程序许可和锁定到Sentinel HASP HL硬件或HASP SL软件产品密钥、管理和跟踪许可证、创建稍后用于产品激活过程等的产品密钥。三个活动分区 在图中显示为垂直泳道,代表 参与活动的 参与者-订单管理、客户服务和客户。客户安装了一些试用产品,例如某些游戏或工具,它们具有特定的试用期,并且可能具有一些有限的功能或选项。使用产品一段时间后,客户决定通过请求永久、完整的产品许可证来激活产品。
订单经理必须为产品创建新的激活密钥,而客户可以创建并交付C2V文件(“计算机指纹”)。一旦新产品密钥和C2V文件可供客户服务使用,它就可以激活产品、生成V2C文件并将其返回给客户。客户应用收到的许可证,从而激活安装的试用产品以成为完整产品。通过HASP SL许可证和保护密钥,可以防止该产品复制到其他计算机或虚拟机。






































