UML 活动图:准则

在 Visual Studio 旗舰版中,可以绘制活动图以按照由一系列操作构成的工作流的形式描述业务流程或软件算法。 这些操作可以由人员、软件组件或设备来执行。 有关视频演示,请参见:Capture Business Workflows by using Activity Diagrams(使用活动图捕获业务工作流)。

若要创建 UML 活动图,请在**“体系结构”菜单上,单击“新建关系图”**。

可以将活动图用于多种目的:

绘制活动图可以帮助您改进流程。 如果现有流程图经证实是非常复杂的,您可以考虑如何简化这一流程。

有关活动图中的元素的参考信息,请参见 UML 活动图:参考

主题内容

与其他关系图的关系

绘制活动图的基本步骤

描述控制流

描述数据流

更详细地定义操作

并发流

与其他关系图的关系

如果绘制活动图来描述业务流程或用户使用系统的方式,则可以绘制用例图来显示相同信息的不同视图。 在用例图中,将操作绘制为用例。 为用例指定与对应的操作相同的名称。 用例视图可以为您带来以下好处:

  • 在一个关系图中,利用“包含”关系来显示较大的操作/用例是如何由多个较小的操作/用例构成的。

  • 将每个操作/用例显式连接到其执行过程中涉及的用户或外部系统。

  • 绘制由您的系统或系统的每个主要组件支持的操作/用例周围的边界。

您还可以绘制活动图来描述软件操作的详细设计。

在活动图中,可以显示操作之间传递的数据流。 请参见描述数据流的相关章节。 但是,活动图不描述数据的结构。 为实现此目的,您可以绘制一个 UML 类图。 有关信息,请参见 UML 类图:准则

绘制活动图的基本步骤

如何:编辑 UML 模型和关系图中介绍了有关创建任何建模图的详细步骤。

绘制活动图

  1. 在**“体系结构”菜单上,单击“新建关系图”**。

  2. 在**“模板”下,单击“UML 活动图”**。

  3. 命名该关系图。

  4. 在**“添加到建模项目”中,从您的解决方案中选择一个现有建模项目,或者选择“创建新的建模项目”**。

在活动图上绘制元素

  1. 将元素从工具箱拖动到关系图上。

    首先将主要活动放置在关系图上,再将这些活动连接起来,然后添加最终的润饰(如初始节点和最终节点)。

    提示

    不能将现有元素从 UML 模型资源管理器拖动到关系图上。

  2. 若要连接这些元素,请按以下步骤进行操作:

    1. 在**“活动图”工具箱中,单击“连接线”**。

    2. 在关系图上,单击源元素。

    3. 单击目标元素。

      提示

      若要多次使用某个工具,请在工具箱中双击该工具。

将一个活动移动到另一个包

  • 在**“UML 模型资源管理器”**中,将此活动拖动到一个包中。

    - 或 -

  • 在**“UML 模型资源管理器”中,右击此活动并单击“剪切”。 然后,右击该包并单击“粘贴”**。

    提示

    此活动仅在您将第一个元素添加到关系图中时显示在 UML 模型资源管理器中。

描述控制流

活动图以一系列操作的形式描述业务流程或软件算法。 连接线箭头显示如何按顺序将控制从一个操作传递到下一个操作。 通常,一个操作只能在其前一个操作完成后开始。

下图是一个示例,它描述如何使用操作、连接线、分支和循环演示一系列操作。 以下各节将更详细地说明每个元素。

一个简单的活动图

活动图使用**“操作”“连接线”**以一系列操作(具有从一个操作到下一个操作的顺序控制流)的形式来描述您的系统或应用程序。

  • 为用户、系统或用户和系统协作执行的每个主要任务创建一个**“操作”**(1)。

    提示

    尝试只使用少量操作来描述流程或算法。 可以使用“调用行为的操作”来更详细地定义单独关系图中的每个操作,如使用调用行为的操作描述子活动中所述。

  • 确保每个操作的标题都清楚地表明操作的典型用途。

  • 使用**“连接线”**(2) 链接序列中的操作。

  • 每个操作都将在控制流中的下一个操作开始之前结束。 若要描述发生重叠的操作,请使用**“分叉节点”**,如并发流一节中所述。

虽然该关系图描述了操作序列,但它不描述操作的执行方法(即,将控制从一个操作传递到下一个操作的方式)。 如果使用该关系图来表示业务流程,则可能会传递控制,例如当一个人向他人发送电子邮件时。 如果使用该关系图来表示软件设计,则可能会通过从一个语句到下一个语句的常规执行流来传递控制。

描述决策和循环

  • 使用**“决策节点”**(3) 指示一个点,此时的决策结果指示下一个步骤。 可以绘制所需数目的传出路径。

  • 如果使用活动图来定义应用程序的一部分,则应定义临界条件 (4),从而清楚地知道何时应采用每条路径。 右击连接线,单击**“属性”,然后在“属性”窗口中的“临界条件”**字段中键入一个值。

  • 并不总是需要定义临界条件。 例如,如果使用活动图来描述业务流程或交互协议,则分支会定义可供用户或交互组件使用的选项范围。

  • 使用**“合并节点”(5) 将在“决策节点”**处分叉的两个或多个替代流组合在一起。

    提示

    应使用“合并节点”将替代流组合在一起,而不是在某个操作中将替代流组合在一起。 在此示例中,从决策节点直接向后连接到“点菜”是不正确的。 这是因为操作在控制线程到达其所有传入连接线之前不会开始。 因此,您只应在一个操作中组合并发流。 有关更多信息,请参见并发流。

  • 使用分支描述循环,如示例中所示。

    提示

    像在程序代码中一样,尝试按照结构完整的方式嵌套循环。 如果描述的是现有业务流程,这样做可能会带来一些改进流程的机会。

启动活动

可以通过两种方式指示活动的入口点:

  • 初始节点

    创建一个**“初始节点”**(6) 以指示活动的第一个操作。

    在描述子活动时或在无需显式声明启动活动的对象时,此方法最有用。 例如,活动“订餐”很明显会在顾客肚子饿的时候启动。

  • 接受事件节点

    如并发流一节中所述创建**“接受事件节点”**,以指示启动一个线程来响应某个特定事件,如用户输入。 不要提供节点的传入流。 忽略传入流指示线程将在每次发生相应事件时启动。

    在描述对某个特定外部事件的响应时,此方法非常有用。

结束活动

使用**“活动最终节点”**(7) 指示活动的结束。

  • 当控制线程到达**“活动最终节点”**时,活动的所有并发操作和子活动都会终止。

  • 可以使用多个活动最终节点来减少其他连接线的混乱程度。

中断活动

若要描述如何中断活动的普通流(例如,如果用户决定取消流程),可以创建一个用于侦听该事件的接受事件节点。 有关更多信息,请参见并发流一节。 创建从一个节点到活动最终节点 (7) 的控制流。

泳道

有时,将活动的多个操作安排到与执行这些操作的各个对象或业务角色相对应的区域中会很有用。 这些区域通常会按列排列,并称为“泳道”。

  • 使用工具箱的**“简单形状”**部分中的线条或矩形来绘制泳道或其他区域。

  • 若要标记每条泳道,请创建注释,并将其**“透明”属性设置为“True”**。

简单形状不构成 UML 模型的一部分,并且不出现在 UML 模型资源管理器中。

描述数据流

您可以使用以下两种方式之一描述传入和传出活动的数据:

  • 使用**“对象节点”**。 这是描述活动之间的信息流动的最简单方法。 对象节点类似于程序中的变量。 它表示用于存储从一个操作传递到另一个操作的一个或多个值的项。

  • 使用**“输出插针”“输入插针”**。 利用此方法,可以分别描述来自一个操作的输出和到另一个操作的输入。 插针类似于程序中的参数。 插针表示对象可通过其进入和离开一个操作的端口。

    提示

    有关本节中使用的元素的概述,请参见UML 活动图:参考主题中的“数据流”一节。

使用对象节点描述数据流

大多数控制流都会传输数据。 例如,来自“客户提供详细信息”操作的输出流会传输对送货地址的引用。

若要在关系图中描述此数据,可以将一条连接线替换为一个对象节点和两条连接线,如下图所示。

对象节点可显示在操作之间传递的数据

请注意,圆角矩形(如“调度货物”)表示正在处理的操作。 方角矩形(如“送货地址”)表示从一个操作到另一个操作的对象流。

为对象节点指定一个名称,此名称反映作为在操作之间流动的对象的管道或缓冲区的节点角色。

可以在属性窗口中设置对象节点的**“类型”**。 类型可以是基元类型(如整型)或已在类图中定义的类、接口或枚举。 例如,您可以创建一个 Shipment Address 类,该类具有 Street Address、City 等特性以及与另一个名为 Customer 的类的关联。 有关更多信息,请参见 UML 类图:准则

提示

如果键入尚未定义的类型的名称,则会在 UML 模型资源管理器中的“未指定的类型”下添加一个项。 如果随后在类图中定义该名称的类型,则应重置对象节点的类型,以使其引用新的类型。

在对象节点中对数据进行缓冲

一个对象节点可用作多个对象的缓冲区。 在下图中,控制流显示用户可以多次访问“[选择更多]”循环 (1),同时“已点的菜”对象节点 (2) 会累积用户的选择。 最后,当用户完成选择时,控制会传递到“确认订单”操作 (3),该操作接受“已点的菜”缓冲区中的完整的选项列表。

在对象节点中对数据进行缓冲

通过设置对象节点的属性,可以指定各个项在缓冲区中的存储方式:

  • 将**“排序”**属性设置为:

    • **“未排序”**可指定随机顺序或未指定的顺序。 (默认。)

    • **“已排序”**可指定基于某个特定键的顺序。

    • **“Fifo”**可指定先进先出的顺序。

    • **“Lifo”**可指定后进先出的顺序。

  • 设置**“上限”**属性可指定缓冲区中可包含的对象的最大数量。 默认值为 *。 这表示不存在任何限制。

使用输入插针和输出插针描述数据流

使用**“输出插针”“输入插针”**可分别描述来自一个操作的输出和到另一个操作的输入。

输入和输出插针是操作参数

若要创建插针,请单击工具箱中的**“输入插针”“输出插针”,然后单击一个操作。 然后,您可以围绕此操作的周边移动插针,并更改其名称。 可以针对任何类型的操作创建输入插针和输出插针,包括“调用行为的操作”“调用操作的操作”“发送信号的操作”“接受事件的操作”**。

两个插针之间的连接线表示一个对象流,如同流入和流出对象节点的流一样。

为每个插针指定一个名称,该名称指示插针生成或接受的对象的角色,如参数名称。

可以在**“类型”**属性中设置传输的对象的类型。 此类型必须是已在 UML 类图中创建的类型。

已连接的插针之间的对象流必须在某些方面是兼容的。 这可能是因为输出插针所生成的对象属于输入插针的类型的派生类型。

或者,可以指定对象流包括一个转换,以在输出插针的类型和输入插针的类型之间进行数据转换。 最常见的此类转换是从更大的类型中提取适当的部分。 图中的示例暗含从“订单详细信息”中提取“送货地址”的转换。

更详细地定义操作

除了通过操作名称来明确指明操作通常应实现的结果之外,还可以通过以下方式为操作添加更多详细信息:

  • 在**“正文”**属性中编写更详细的说明。 例如,可以编写程序代码或伪代码的片段,或编写所实现的结果的完整说明。

  • 将操作替换为调用行为的操作,并在单独的活动图中描述其详细行为。 请参见使用调用行为的操作描述子活动。

  • 设置操作的**“本地后置条件”“本地前置条件”**属性以更详细地描述操作的结果。 有关更多信息,请参见定义后置条件和前置条件。

使用调用行为的操作描述子活动

可以使用单独的活动图来描述操作的详细行为。 被调用行为是一个活动图,它在主活动图中由调用行为的操作表示。 还可以使用调用行为的操作来描述在不同的活动之间共享的行为,从而使您不必多次绘制子活动。

在下图中,关系图 1 显示具有调用行为的操作的活动;关系图 2 显示一个子活动图,其中显示了被调用行为。

单独的活动图显示详细的操作

使用调用行为的操作描述子活动

  1. 若要为子活动创建关系图,请在**“解决方案资源管理器”中右击建模项目,指向“添加”,再单击“新建项”**。

  2. 添加新项对话框中,单击**“模板”下的“活动图”,然后在“名称”框中键入计划为“调用行为的操作”**指定的名称。

  3. 为子活动绘制详细的工作流。 这是被调用行为。

    • 在被调用子活动图中,**“初始节点”**指示在调用被调用行为时控制开始的位置。 **“活动最终节点”**显示控制应返回到父活动的位置。
  4. 设置**“调用行为的操作”“行为”**属性以引用被调用行为关系图。

    提示

    子活动图必须具有此操作的某些元素,否则该图将不会“行为”属性的下拉列表中出现。 此外,在设置其“行为”属性之前,三叉戟图标将不会在“调用行为的操作”形状中出现。

  5. 设置操作的**“是同步的”**属性以指示您的活动是否等待被调用的活动完成。

    • 如果将**“是同步的”**设置为 false,则表示在被调用的活动完成之前,控制流可以继续执行下一个操作。 不应在操作中定义输出插针或传出数据流。

描述在子活动中流入和流出的数据流

可以按照在软件中使用参数的方式来描述在子活动中流入和流出的数据流。

  • 在调用行为的操作中为流入或流出操作的每段数据创建输入插针和输出插针 (1)。 为每个插针指定适当的名称。

  • 在子活动图中,为调用操作中的每个输入插针和输出插针创建**“活动参数节点”**(2)。 为每个节点指定与其所对应的插针相同的名称。

    提示

    活动参数节点类似于对象节点。 要了解正在查看的节点的类型,请右击该节点,然后单击“属性”。 节点类型将显示在“属性”窗口的标题中。

  • 在子活动图中绘制连接线,这些连接线将显示流入或流出每个活动参数节点的对象流。

映射到活动参数的调用行为上的插针

定义后置条件和前置条件

可以使用**“本地后置条件”“本地前置条件”**属性来详细地指定操作的结果。 这些属性描述操作的结果,而不描述如何实现该结果。

若要设置这些属性,请右击该操作,然后单击**“属性”**。 在“属性”窗口中的相关属性中键入值。

本地后置条件

后置条件是指在将操作视为已完成之前应先满足的条件。 在示例操作“确认订单”中,后置条件可能为:

客户提供了处理其信用卡所需的完整有效的详细信息。

后置条件可以表示操作发生前后的状态之间的关系。 例如:

利息与以前相比翻倍。

可以通过引用操作中已处理的数据的特定特性,采用更为正式的方式来编写后置条件。 例如:

InvoiceTotal == Sum(OrderItem.MenuItem.Price)

前置条件

前置条件是指在准备开始某个操作时应为 true 的条件。 例如,“确认订单”操作可能具有以下前置条件:

客户从菜单中选择了至少一个菜。

描述对操作的调用

通常,操作描述的是由人员、软件或机器的任意组合来执行的工作。 但是,可以使用调用操作的操作来描述对特定软件的方法或函数的调用。

  • 设置调用操作的操作的名称以指示被调用的操作,以及被调用的操作所针对的对象或组件。

  • 向调用操作的操作中添加输入插针和输出插针以描述参数和返回值。

  • 可以设置操作的**“是同步的”**属性以指示您的活动是否等待该操作完成。

    • 如果将**“是同步的”**设置为 false,则表示在被调用操作完成之前,控制流可以继续执行下一个操作。 不应在操作中定义输出插针或传出数据流。

并发流

可以使用**“分叉节点”“联接节点”**来描述可同时执行的活动的两个或多个线程。

分叉和联接节点显示并发流

“分叉节点”(1) 的作用是将控制线程划分为两个或多个线程。 当上一个操作结束时,分叉输出端的所有操作便可以开始。

“联接节点”(2) 可将并发线程连接在一起。 在通向**“联接节点”的所有操作完成之前,“联接节点”**后面的操作将无法开始。

描述信号和事件

可以将进程中发送信号的步骤显示为活动中的发送信号的操作。 可以将需等待特定的信号或事件后才能继续执行的步骤显示为接受事件的操作。

例如,您可能显示一个发送订单的步骤,然后再显示另一个必须在收到订单后才处理订单的步骤。

发送信号

使用发送信号的操作 (3) 可指示将某类信号或消息发送到其他活动或进程。 使用此操作的名称可指示操作所发送的消息的类型。

  • 控制立即传递到控制流中的下一个操作(如果有的话)。

  • 不能使用发送信号的操作来描述进程如何响应任何返回的信息。 为此,请使用单独的接受事件的操作。

  • 可以显示传递到发送信号的操作的传入数据流以指示可以将哪些数据与传出消息一起发送。 有关更多信息,请参见描述数据流。

等待信号或事件

使用接受事件的操作 (4) 可指示此活动等待某些外部事件或传入消息。 使用此操作的名称可指示活动所等待的事件的类型。

  • 若要显示活动在流中某个特定点等待外部事件或消息,请在活动中的适当位置绘制带有传入流的接受事件的操作。

  • 若要显示活动可以随时响应外部事件或消息,请绘制不带任何传入流的接受事件的操作。 当发生指定的外部事件时,活动中将启动一个从接受事件的操作开始的新线程。

  • 不能使用接受事件的操作来描述返回给信号发送方的任何值。 为此,请使用单独的发送信号的操作。

  • 可以显示操作中的传出数据流,以演示活动如何处理通过信号收到的数据。 若要显示多个输出流,则应设置接受事件的操作的**“IsUnmarshall”**属性,此属性指示该操作将传入信号分析为其单独的组件。 有关更多信息,请参见描述数据流。

描述多个数据流

可以绘制随操作出现的多个控制流或对象流,以指示在操作结束时多个线程将合并。 其效果与分叉类似,只不过您可以混合使用控制流和对象流。

下面的示例显示流入和流出操作的多个流。

并行对象流

当“客户提供详细信息”操作完成时,将会产生两个对象,即“送货地址”和“信用卡详细信息”。紧接着,将通过不同的操作来处理这两个对象。

由于操作需要在其所有输入都可用后才能开始,因此最后一个操作在通向它的所有操作完成前不会开始。

可以使用活动图来帮助您描述管道或同时执行的一系列操作,并连续地将数据从一个操作传递到另一个操作。

以下示例旨在阐明每个操作都可以生成对象并继续工作。 由于没有控制流,因此每个操作在收到它的第一个对象时都会启动。

请注意,此示例中的连接线都是对象流,因为这些连接线至少有一端位于活动参数节点、对象节点或输入插针/输出插针上。

一个数据流

1. 此示例具有三个活动参数节点,表示其输入和输出。

2. 对象节点、输入插针和输出插针都可以表示缓冲区。 可以设置对象节点的“上限”属性以指明可同时位于缓冲区中的对象数目。

3. 可以使用决策节点来显示分流,即将各个对象向下发送到不同的分支。 可以使用注释或节点标题来说明分流标准。

4. 可以使用分叉节点来显示为对象制作两个或多个副本,并发送它们以供并发处理。

5. 可以使用联接节点来显示将两个处理流合并成一个流。

选择和转换

可以指定选择或转换对象流中的对象,或者选择并转换对象流中的对象。 对象流是在插针或对象节点中流入/流出的流。

  • 转换描述如何将进入流的对象转换为另一种类型。

  • 选择描述如何仅将进入流的某些对象传输到接收操作。

该示例演示了一个转换。 关系图 1 中的第一个操作会在一个输出插针上生成一个邮政编码。 在第二个操作中,该输出插针会连接到一个输入插针。 不过,第二个操作需要的是完全指定的地址。 另一个活动“地址查找”中指定了从一个类型到另一个类型的转换。 此转换引用自对象流的“转换”属性。 “地址查找”活动包含两个活动参数节点,一个用于传入邮政编码,另一个用于传出完整地址。

另一个关系图中定义的对象变换

可以通过以下两种方式指定转换或选择:

  • 将注释附加到输入插针或输出插针。

    • 若要使此说明有别于一般注释,可以使用 <<transformation>> 或 <<selection>> 作为注释的开头。
  • 在单独的活动图中详细指定转换或选择。

    • 如果使用此方法,也请附加注释,以让读者明白已定义了转换。

在单独的活动图中指定转换或选择

  1. 创建新的活动图,在其中描述转换或选择流。

    • 在**“解决方案资源管理器”中,右击项目,指向“添加”,再单击“新建项”,然后单击“活动图”。 针对转换或选择流,为此关系图指定一个适当的名称。 单击“添加”**。
  2. 在新的关系图中:

    1. 创建两个活动参数节点,一个用于输入流,一个用于输出流。

    2. 创建与对象流相互连接的操作。 这显示了转换或选择操作的工作方式。

  3. 在要使用转换或选择的任何关系图中:

    1. 创建一个对象流(即,连接输入插针/输出插针、对象节点或活动参数节点的连接线)。

    2. 右击该对象流,再单击**“属性”**。

    3. 在**“转换”“选择”**属性中,选择在其中指定了转换或选择流的关系图。

此外,可以为对象节点定义选择,也可以在各个输入插针和输出插针上定义选择。 按照与上一个步骤相同的方式定义一个选择活动,然后设置对象节点或输入插针/输出插针的**“选择”**属性。

请参见

参考

UML 序列图:参考

概念

如何:编辑 UML 模型和关系图

UML 组件图:参考

UML 用例图:参考

UML 类图:参考

UML 组件图:参考

其他资源

Video: Capture Business Workflows by using Activity Diagrams(视频:使用活动图捕获业务工作流)