前言
一图胜过万言,这是在实习中我深刻体会到的。以前自己很抗拒画图,根本原因是自己不会画。但在梳理自己文章时发现,图好像能“说”一些文字不能表达的简洁和严谨,这点倒是喜出望外的,既让自己舒服更让别人舒服(前提是自己肯静下来花功夫画好图)。
因此“会”画图,真的很有必要,无论是在细分、总结、梳理、汇报、分享等等的文字出现的地方,都能发挥意料之外的力量。
UML 概述
而选择一种图来编写也显得尤其重要,所以个人粗略通过这篇文章,总结学习一下 UML 图。
什么是 UML
一句话
**UML(Unified Modeling Language,统一建模语言)**是用来设计软件蓝图的可视化建模语言,是一种为面向对象系统的产品进行说明、可视化和编制文档的标准语言,独立于任何一种具体的程序设计语言。是 OMG 统一建模语言。
此 OMG 不是大哥上路的 OMG,是对象管理组织是一个国际协会,开始的目的是为分布式面向对象系统建立标准,现在致力于建立对程序、系统 和业务流程的建模标准,以及基于模型的标准。
建模是啥
是在编码之前设计软件应用程序。
UML 建模的核心是模型,模型是现实的简化、真实系统的抽象。 当给软件系统建模时,需要采用通用的符号语言,这种描述模型所使用的语言被称为建模语言。在 UML 中,所有的描述由事物、关系和图这些构件组成。下图完整地描述了所有构件的关系。
笔记
- 结构事物是图用来描述概念或实体的。
- 行为事物其实就是结构事物之间的行为动作。
- 分组事物中包,类似 JS 中的库概念。
- 注释就是解释。
UML 2.0 定义了十三种图
- 结构图(静态应用结构) 包括类图、对象图、组件图、组合结构图、包图和部署图。
类图:定义系统中的类。
对象图:类图的一个实例,描述了系统在具体时间点上所包含的对象及各个对象之间的关系。
组件图:描述物理系统一部分的图。
组合结构图:表示类或者构建内部结构的图。
包图:对构成系统的模型元素进行分组整理的图。
部署图:定义系统中软硬件的物理体系结构。
- 行为图(一般的行为类型) 包括用例图、活动图和状态图。
- 用例图:描述用户的需求,从用户的角度描述系统的功能,并指出各功能的执行者,强调谁在使用系统、系统为执行者完成哪些功能。
- 活动图:描述满足用例要求所要进行的活动及活动间的约束关系。
- 状态图:描述类的对象的所有可能的状态和时间发生时,状态的转移条件。
- 交互图(交互的不同方面) 包括序列图、通信图、时序图和交互概述图。(交互图都是从更一般的行为图派生的)
- 序列图:显示在系统中参与者和对象之间传递的消息,以及消息的发生顺序。
- 通信/协作图: 描述对象之间的合作关系,更侧重向用户对象说明哪些对象有消息的传递。
- 时序图:面熟对象之间的交互顺序,着重体现对象间消息传递的时间顺序,强调对象之间消息的发送顺序,同时显示对象之间的交互过程。
- 交互概览图:用活动图来表示多个交互之间的控制关系的图
总结
模型在软件开发中扮演的角色与蓝图和其他计划(站点地图、立面图、物理模型)在建造摩天大楼中扮演的角色类似。
使用模型,负责软件开发项目成功的人员可以确保业务功能完整且正确,满足最终用户的需求,并且程序设计支持对可伸缩性、稳健性、安全性、可扩展性和其他特性的要求,之前代码中的实现使更改变得困难且昂贵。
语言是啥
语言不止是文字,有很多内容文字是无法表达的,也就是用图片来表达。类似在建筑界,建筑设计图纸有一套标准来描述设计。同样,在软件开发界,UML 就是其中的一种标准,注意这可不是唯一标准,只是 UML 是大家比较推崇的一种标准而已。
因此UML 并不是强制性标准,没有规定在软件开发中一定要用 UML,但是我们需要包括 UML 在内的各种标准,来提高我们软件开发的水平。
优点是啥
- 提高抽象级别
模型通过让我们在更高的抽象层次上工作来帮助我们,可以通过隐藏或掩盖细节、展现大局或关注原型的不同方面来做到这一点。
- 用于做工具分析来逆向工程为一组 UML 图
- 与硬件、操作系统无直接关联,可以是独立于平台的,也可以是特定于平台的。
- UML 模型独立于方法论
无论您使用何种方法来执行分析和设计,都可以使用 UML 来表达结果。并且,您可以将您的 UML 模型从一个工具转移到存储库中,或转移到另一个工具中以进行细化或您选择的开发过程的下一步。
- 逻辑理解可视化
UML 图
秉承着要用才学,不用会忘,忘了白学的原则,个人重点学习以下几种图:用例图、类图、时序图、活动图(流程图)。
用例图
用来记录系统的需求,它提供系统与用户及其他参与者的一种通信手段。
下列用例图均自官方参考
组成元素
用例图显示了系统和系统外实体之间的交互,实体引用为执行者,系统由系统内部用例组成,因此用例图关键由执行者和用例组成,
执行者
执行者代表角色,可以包括:用户,外部硬件和其他系统。
执行者往往被画成简笔画小人。也可以用带«actor»关键字的类矩形表示。
执行者也可以用作详细地泛化其他执行者:
用例
用例是有意义的单独工作单元。它向系统外部的人或事提供一个易于观察的高层次行为视图。
用例的标注符号是一个椭圆。
使用用例的符号:是带可选择箭头的连接线,箭头显示控制的方向。
这图说明执行者 "Customer"使用 "Withdraw"用例。
用途连接器:可以有选择性的在每一个端点有多重性值。
显示客户一次可能只执行一次取款交易。但是银行可以同时执行许多取款交易。
一个典型的用例定义包括:
- 名称和描述
用例通常用一个动词词组定义,而且有一个简短的文字说明。
- 需求
需求定义了一个用例必须提供给终端用户的正式功能性需求。它们符合构造方法建立的功能性规范。一个需求是用例将执行一个动作或提供多个值给系统的约定或承诺。
- 约束
一个约束是一个用例运行的条件或限制。
它包括:前置条件,后置条件和不变化条件 。
- 前置条件指明了用例在发生之前需要符合的条件。
- 后置条件用来说明在用例执行之后一些条件必须为"真"。
- 不变化条件说明用例整个执行过程中该条件始终为"真"。
- 情形
情形是用例的实例在执行过程中,事件发生流程的形式描述。它定义了系统和外部执行者之间的事件指定顺序。 通常用文本方式来表示,并对应顺序图中的文字描述。
- 包含用例
用例可能包含其他用例的功能来作为它正常处理的一部分。通常它假设,任何被包含的用例在基本程序运行时每一次都会被调用。
下面例子:用例“卡的确认” 在运行时,被用例“取钱”当作一个子部分。提现用例可以为通用行为,将其可以变成多次重复使用的用例。
- 扩展用例
一个用例可以被用来扩展另一个用例的行为,通常使用在特别情况下。
例如:假设在修改一个特别类型的客户订单之前,用户必须得到某种更高级别的许可,然后“获得许可”用例将有选择的扩展常规的“修改订单”用例。
- 扩展点
扩展用例的加入点被定义为扩展点。
- 系统边界
它用来显示用例在系统内部,执行者在系统的外部。
示例
类图
类图展示了面向对象系统的构造模块。描绘了模型或部分模型的静态视图,显示它包含的属性和行为,而不是详细描述操作的功能或完善方法。
类图最常用来表达多个类和接口之间的关系。泛化(Generalizations),聚合(aggregations)和关联(associations)分别是类之间继承,复合或应用,及连接的表现。
元素组成
类(Classes)
类(Classes)是定义对象所具有的属性和行为的元素。行为用类能理解的合适消息和适合每条消息的操作来描述。 类中也可能定义约束,标记值,构造型。
类的标柱(Class Notation)
类的标注(Class Notation)用矩形表示。除类的名称外,还可以选择性地显示属性和操作。 分栏分别用来显示类的名称,属性和操作。
在下面图中:
类的类名显示在最上面的分栏(Rectangle),它下面的分栏显示详细属性。
最后面的分栏显示操作,如: setWidth,setLength 和 setPosition 以及他们的参数。
属性和操作名前的标注表示了该属性或操作的可见性:
"+"号属性或操作是公共的 ;
"-" 号则代表这个属性或操作是私有的。
"#"号是这个属性或操作被定义为保护的,
" ~" 号代表包的可见性。
接口(Interfaces)
接口是实施者同意满足的行为规范,是一种约定。实现一个接口,类必需支持其要求的行为,使系统按照同样的方式,即公共的接口,处理不相关的元素。
接口有相似于类的外形风格,含有指定的操作,如下图所示。如果没有明确的详细操作,也可以画成一个圆环。当画成圆环的时候,到这个环形标柱的实现连接没有目标箭头。
表(Tables)
表尽管不是基本UML的一部分,仍然是“图型”能完成的实例用。
在右上角画一个表的小图标来表示。
表属性用“图型” «column»表示。
绝大多数表单有一个主键,是由一个或几个字段组成的一个唯一的字码组合加主键操作来访问表格,主键操作“图型”为«PK»。
一些表有一个或多个外键,使用一个或多个字段加一个外键操作,映射到相关表的主键上去,外键操作“图型”为«FK»。
类关系
关联(Associations)
关联表明两个模型元素之间有关系,通常用在一个类中被实现为一个实例变量。连接符可以包含两端的命名的角色,基数性,方向和约束,关联是元素之间普通的关系。如果多于两个元素,也可以使用菱形的关联关系。当从类图生成代码时,关联末端的对象将变成目标类中实例变量。
见下图示例 "playsFor" 将变成"Player"类中的实例变量。
泛化(Generalizations)
泛化被用来说明继承关系。连接从特定类元到一般类元。泛化的含义是源类继承了目标类的特性。
图显示了一个父类泛化一个子类, 类“Circle”的一个实例将会有属性 “ x_position”,“ y_position” , “radius” 和 方法 “display()”。
注意:类 "Shape" 是抽象的,类名显示为斜体。
下图显示了与上图相同信息的视图。
聚合(Aggregations)
聚合通常被用来描述由更小的组件所构成的元素。
聚合关系(弱聚合)- 表示为白色菱形箭头指向目标类或父类。
如果一个部件从组合中去掉,将不用删除整个组合。组合是可迁,非对称的关系和递归的。
聚合的更强形式 -组合聚合(强聚合) - 显示为黑色菱形箭头。
用来组合每次最大化的包含组件。如果一个组合聚合的父类被删除,通常与他相关的所有部分都会被删除。
图示:显示了弱聚合和强聚合的不同。
- “ address book” 由许多 “contacts” 和 “contact groups”组成。
- “contact group” 是一个“contacts”的虚分组;
- 强聚合:如果删除一个“ address book”,所有的 “contacts” 和 “contact groups” 也将会被删除;
- 弱聚合:如果你删除“ contact group”, 没有 “contacts”会被删除。
关联类(Association Classes)
关联类是一个允许关联连接有属性和操作的构造。
示例:显示了远不止简单连接两个类的连接,
如给“employee”分配项目。“ employee”在项目中所起的作用是一个复杂的实体,既有自身的也有不属于“employee” 或 “project” 类的细节。
例如,“ employee”可以同时为几个项目工作,有不同的职务头衔和对应的安全权限。
依赖(Dependencies)
依赖被用来描述模型元素间广泛的依赖关系。
通常在设计过程早期显示两个元素之间存在某种关系,因为是初期而不能确定具体是什么关系,在设计过程末期,该继承关系会被归入已有构造型 (构造型可以是实例化 «instantiate»,跟踪 «trace»,导入 «import», 和其它的关系),或被替换成一个更明确类型的连接符。
跟踪(Traces)
跟踪关系是一种特殊化的依赖关系。
连接模型元素或跨模型但是具有相同概念的模型元素集。跟踪被经常用来追踪需求和模型的变化。由于变化是双向的,这种依赖关系的顺序通常被忽略。这种关系的属性可以被指定为单向映射,但跟踪是双向的,非正式的和很少可计算的。
实现(Realizations)
是源对象执行或实现目标,实现被用来表达模型的可跟踪性和完整性-业务模型或需求被一个或多个用例实现,用例则被类实现,类被组件实现,等等。
这种实现贯穿于系统设计的映射需求和类等,直至抽象建模水平级。从而确保整个系统的一张宏图,它也反映系统的所有微小组成,以及约束和定义它的细节。实现关系用带虚线的实箭头表示。
嵌套(Nestings)
嵌套连接符用来表示源元素嵌套在目标元素中。下图显示“ inner class”的定义,尽管在EA中,更多地按照着他们在项目层次视图中的位置来显示这种关系。
示例
时序图
时序图是交互图的一种形式,它显示对象沿生命线发展,对象之间随时间的交互表示为从源生命线指向目标生命线的消息。
时序图能很好地显示那些对象与其它那些对象通信,什么消息触发了这些通信,但不能很好显示复杂过程的逻辑。
元素组成
生命线
一条生命线在时序图中代表一个独立的参与者。
表示为包含对象名的矩形,如果它的名字是"self",则说明该生命线代表控制带顺序图的类元。
顺序图会包含一个顶端是执行者的生命线。这情况说明掌握这个顺序图的是用例。健壮图中的边界,控制和实体元素也可以有生命线。
消息
消息显示为箭头。
消息可以完成传输,也可能丢失和找回,它可以是同步的,也可以是异步的,即可以是调用,也可以是信号。
第一条消息是同步消息(标为实箭头)完成传输,并隐含一条返回消息。
第二条消息是异步消息 (标为实线箭头),
第三条是异步返回消息(标为虚线)。
门
**门是连接片段内消息和片段外消息的连接点。**在EA中,门显示为片段框架上的小正方形。作用为时序图与页面外的连接器。 用来表示进来的消息源,或者出去消息的终点。
下面两个图显示它们在实践中的使用。注意:" top level diagram"中的门用消息箭头指向参考片段,在这里没有必要把它画成方块。
行为
生命线开始与结束
生命线可以在顺序图时间刻度范围内创建和销毁。
图中表示 Parent 生命线创建 Child 生命线并将其销毁。
执行发生
向下延伸的细条状矩形表示执行事件或控制焦点的激活。
内部通信
显示为生命线上执行事件的嵌套控制焦点。
内部消息表现为一个操作的递归调用,或一个方法调用属于同一个对象的其他方法。
迷路消息和拾取消息
迷路消息是那些发送了却没有到达指定接收者,或者到达的接收者不再当前图中。
拾取消息是收到来自那些未知的发送者,或者来自没有显示在当前图的发送者的消息。
它们都表明是去往或来自一个终点元素。
时间和期限约束
消息默认显示为水平线。
因为生命线显示为沿屏幕向下的时间通道,所以当给实时系统建模,或是有时间约束的业务过程建模,考虑执行动作所需时间长度是很重要的。
因此可以给消息设置一个期限约束,这样的消息显示为下斜线。
复合片段
如开头所说,顺序图不适合表达复杂的过程逻辑。在一种情况下,有许多机制允许把一定程度的过程逻辑加入到图中,并把它们放到复合片段的标题下。
复合片段是一个或多个处理顺序被包含在一个框架中,并在指定名称的环境下执行。 例子如下:
- 选择性片段 (显示 “alt”) 为 if…then…else 结构建模。
- 选项片段 (显示 “opt”) 为 "switch"(开关) 结构建模。
- 中断片段对被处理事件的可选择顺序建模,而不是该图的其他部分。
- 并行片段(显示 “par”) 为并发处理建模。
- 弱顺序片段 (显示 “seq”) 包含了一组消息,这组消息必须在后继片段开始之前被处理。但不会把片段内消息的先后顺序强加到不共享同一条生命线的消息上。
- 严格顺序片段 (显示 “strict”) 包含了一系列需要按照给定顺序处理的消息。
- 非片段 (显示 “neg”) 包含了一系列不可用的消息。
- 关键片段 具有关键部分。
- 忽略片段 声明一个没有意义的消息,如果它出现在当前上下文中。
- 考虑片段与忽略片段相反,不包含在考虑片段内的消息都应该被忽略。
- 断言片段 (显示 “assert”)标明任何没有显示为声明操作数的顺序都是无效的。
- 循环片段 包含一系列被重复的消息。
循环片段例子:
将被参考图名显示在方框的中间。
部分分解
一个对象可以引出多条生命线,使得对象内部和对象之间的消息显示在同一图上。
状态常量
状态常量是生命线的约束,运行时始终为"真"。显示为两侧半圆的矩形,如下图:
延续
延续虽与状态常量有同样的标注,但是被用于复合片段,并可以延伸跨越多条生命线。
示例
活动图
UML中,活动图用来展示活动的顺序。显示了从起始点到终点的工作流,描述了活动图中存在于事件进程的判断路径。
活动图可以用来详细阐述某些活动执行中发生并行处理的情况。活动图对业务建模也比较有用,用来详细描述发生在业务活动中的过程。
元素组成
活动
活动是行为参数化顺序的规范。活动被表示为圆角矩形,内含全部的动作,工作流和其他组成活动的元素。
动作
一个动作代表活动中的一个步骤。动作用圆角矩形表示。
动作约束
动作可以附带约束,下图显示了一个带前置条件和后置条件的动作。
控制流
控制流显示一个动作到下一个动作的流。表示为带箭头实线
初始节点
一个开始或起始点用大黑圆点表示,如下图。
结束节点
结束节点有两种类型:活动结束节点和流结束节点。
- 活动结束节点表示为中心带黑点的圆环。
- 流结束节点表示为内部为叉号的圆环。
这两种不同类型节点的区别为:流结束节点表明单独的控制流的终点。活动结束终点是活动图内所有控制流的结束。
对象和对象流
对象流是对象和数据转递的通道。
- 对象显示为矩形。
- 对象流显示为带箭头的连接器,表明方向和通过的对象。
一个对象流在它的至少一个终端有一个对象。在上图中,可以采用带输入输出引脚的速记标柱表示。
- 数据存储显示为带 «datastore» 关键字的对象。
判断节点和合并节点
判断节点和合并节点是相同标注:菱形。它们可以被命名。
从判断节点出来的控制流有监护条件,当监护条件满足时,可以对流控制。下图显示了判断节点和合并节点的使用。
分叉和结合节点
分叉和结合节点有同样的标柱:垂直或水平条(方向取决于工作流从左到右,还是从上到下)。
它们说明了控制的并发线程的起始和终点,下图显示他们的使用示例。
结合节点与合并节点不同之处在于:结合节点同步两个输入量,产生一个单独的输出量。来自结合节点的输出量要接收到所有的输入量后才能执行。合并节点直接将控制流传递通过。
如果两个或更多的输入量到达合并节点。则它的输出流指定的动作会被执行两次或更多次。
扩展域
扩展域是会执行多次的结构活动域。
输入输出扩展节点表示为一组“3厢” ,代表多个选择项。关键词 "iterative", "parallel" 或 "stream"显示在区域的左上角
异常处理器
异常处理器在活动图中可以建模。
可中断活动区
可中断活动区环绕一组可以中断的动作。
当控制被传递到结束订单 "Close Order" 动作,定单处理"Process Order" 动作会执行直到完成,除非"Cancel Request"取消请求中断被接受,这会将控制传递给"Cancel Order"动作。
分割
一个活动分割显示为垂直或水平泳道。在下图中,分割被用来在活动图中分隔动作,有在 "accounting department"中执行的,有在 "customer"中执行的。
示例
参考
温故而知新~~
维基百科