开始这堂关于状态图 (State Diagram) 的课程。这是一种非常强大的图表,专门用来描述一个对象或系统在其生命周期内,所经历的各种状态以及状态之间转换的规则

如果说流程图是描述一个“过程”,那么状态图就是描述一个“事物”的“一生”。

本课程的所有示例都非常简短,强烈建议您打开 Mermaid 官方的在线编辑器 mermaid.live,一边学习一边亲手尝试下面的每一个小步骤。


第二部分:常用图表绘制

第7章:状态图 (State Diagram) - 建模对象生命周期

好比说:我们来思考一个最简单的“电灯”的生命周期。它只有两种状态:“关”和“开”。而导致状态变化的事件是“按开关”。状态图就是用来清晰地描绘这种关系的。

7.1 状态图声明与状态定义 (stateDiagram-v2)

第一步:声明图表类型

任何一个状态图,都必须stateDiagram-v2 这个关键字开头。v2 代表这是新版本的状态图语法,功能更强大,我们应该始终使用它。

我们先写下这最基本的第一行:

代码段

stateDiagram-v2

这行代码会创建一个空白的状态图画布。

第二步:隐式地定义状态

最简单的方式,就是直接在描述“转换”关系时提到状态的名字,Mermaid会自动创建它们。

代码段

stateDiagram-v2
  Off --> On

这行代码就自动为我们创建了两个状态:Off(关)和 On(开)。

第三步:显式地定义状态

当你需要为状态提供一个更具描述性的别名,或者定义更复杂的复合状态时,可以使用 state 关键字。

语法: state "要显示的文本" as 状态ID

代码段

stateDiagram-v2
  state "等待中" as Waiting
  state "运行中" as Running

这里我们定义了两个状态,它们的ID是WaitingRunning,但在图上会显示为中文“等待中”和“运行中”。


7.2 定义状态转换 (-->)

1. 核心概念

状态转换,指的是一个对象从一个状态迁移到另一个状态的过程。这个过程通常是由一个事件 (Event) 触发的。

2. 一步一步定义转换

第一步:使用箭头 -->

我们使用箭头 --> 来表示一个状态可以转换到另一个状态。

代码段

stateDiagram-v2
  Off --> On
  On --> Off

这表示“关”状态可以转换到“开”状态,反之亦然。

第二步:为转换添加标签(描述事件)

这是状态图中至关重要的一步。我们需要在箭头上添加文本,来说明是什么事件导致了这个状态转换。

语法: 状态1 --> 状态2 : 事件描述

代码段

stateDiagram-v2
  Off --> On : press_switch
  On --> Off : press_switch

现在这个图的含义就非常清晰了:无论是从“关”到“开”,还是从“开”到“关”,触发的事件都是 press_switch(按开关)。


7.3 定义起始与结束状态 ([*])

1. 核心概念

一个完整的生命周期,应该有明确的起点和终点。

好比说:一个订单的生命周期,从“创建”(起点)开始,到“已完成”或“已取消”(终点)结束。

2. 一步一步定义

第一步:定义起始状态

使用 [*] 符号代表起始点,它是一个实心圆。

代码段

stateDiagram-v2
  # 从起始点转换到“待支付”状态
  [*] --> PendingPayment

第二步:定义结束状态

同样使用 [*] 符号代表结束点,它是一个带圆圈的实心圆。

代码段

stateDiagram-v2
  # “已完成”状态可以转换到结束点
  Completed --> [*]
  # “已取消”状态也可以转换到结束点
  Cancelled --> [*]

第三步:组合一个简单的生命周期

代码段

stateDiagram-v2
  [*] --> PendingPayment : create_order
  PendingPayment --> Processing : pay
  Processing --> Completed : ship
  Completed --> [*]

这个图清晰地描述了一个订单从创建到完成的“快乐路径”。


7.4 复合状态(嵌套)

1. 核心概念

有时候,一个状态本身可能就非常复杂,它内部还包含自己的一套子状态。这种“状态中的状态”,就叫做复合状态

好比说:“听音乐”是手机的一个状态。但“听音乐”这个大状态里面,又可以细分为“正在播放”、“已暂停”、“正在缓冲”这几个子状态

2. 一步一步定义复合状态

第一步:使用 state 和花括号 {} 定义复合状态

代码段

stateDiagram-v2
  # 定义一个名为 "MusicPlayer" 的复合状态
  state "听音乐" as MusicPlayer {
    # 嵌套的子状态图将写在这里
  }

第二步:在复合状态内部定义子状态和转换

代码段

stateDiagram-v2
  state "听音乐" as MusicPlayer {
    # 子状态图也有自己的起始点
    [*] --> Paused
    Paused --> Playing : play_button
    Playing --> Paused : pause_button
  }

第三步:定义进出复合状态的转换

代码段

stateDiagram-v2
  [*] --> Idle : open_app

  state "听音乐" as MusicPlayer {
    [*] --> Paused
    Paused --> Playing : play_button
    Playing --> Paused : pause_button
  }
  
  Idle --> MusicPlayer : select_song
  MusicPlayer --> Idle : close_player

现在,这个图就完整地描述了:应用打开后进入Idle状态,选歌后进入MusicPlayer这个大状态,并在其内部的PausedPlaying子状态间切换,最后关闭播放器又回到Idle状态。


7.5 并发状态(Forks and Joins)

1. 核心概念

并发状态用于描述一个系统可以同时处于多个独立的状态区域。

好比说:你在“工作”这个大状态中,可以同时处于“用键盘打字”和“用耳机听歌”这两个并行的子状态。这两个子状态互不干扰,同时发生。

2. 一步一步定义并发状态

第一步:使用 -- 分割线

在复合状态内部,我们使用 -- 分割线来创建并行的区域。

第二步:定义一个包含并发区域的复合状态

代码段

stateDiagram-v2
  state "文档处理中" as Processing {
    # 使用 -- 分割成两个并发区域
    ImageHandling
    --
    TextHandling
  }

第三步:为每个并发区域定义自己的状态流

代码段

stateDiagram-v2
  [*] --> Processing

  state "文档处理中" as Processing {
    state "图片处理" as ImageHandling {
      [*] --> Resizing
      Resizing --> Compressing
      Compressing --> [*]
    }
    --
    state "文本处理" as TextHandling {
      [*] --> SpellCheck
      SpellCheck --> Formatting
      Formatting --> [*]
    }
  }

  Processing --> [*]

这个图表示,当进入“文档处理中”状态后,“图片处理”和“文本处理”这两条流水线会同时开始工作。


7.6 为状态和转换添加注释与描述

第一步:为状态添加描述

你可以在状态框的标题下方,为其添加更详细的文字描述。

语法状态ID : 描述文字

代码段

stateDiagram-v2
  state "正在验证" as Validating
  Validating : 正在调用第三方API
  Validating : 检查用户凭证...

这会在“正在验证”这个状态框里,显示出下面两行描述文字。

第二步:为转换添加注释 (note)

如果你想为某个状态或转换添加一段更长的、像便利贴一样的注释,可以使用note

语法note [right of | left of] 状态ID : 注释内容 end note

代码段

stateDiagram-v2
  [*] --> Idle

  note right of Idle
    这是系统的初始状态。
    它正在等待外部事件的触发。
  end note

这会在Idle状态的右边,生成一个带箭头的注释框。


7.7 选择点 (Choice Points)

1. 核心概念

选择点用于表示一个基于条件判断的动态转换。它允许一个流程在离开当前状态后,根据不同的条件,进入到不同的下一个状态。

好比说:一个订单在“已支付”状态后,会进入一个“检查点”(选择点)。在这个检查点,系统会判断“订单金额是否大于100元”。如果,则进入“需要人工审核”状态;如果,则直接进入“自动发货”状态。

2. 一步一步定义选择点

第一步:使用 <<choice>> 定义一个选择点状态

代码段

stateDiagram-v2
  # C1是我们给这个选择点起的名字
  state C1 <<choice>>

它在图上会被渲染成一个菱形。

第二步:将流程引导至选择点

代码段

stateDiagram-v2
  Paid --> C1 : check_amount
  state C1 <<choice>>

第三步:从选择点引出带条件的转换

条件的语法是 [条件描述]

代码段

stateDiagram-v2
  state C1 <<choice>>
  C1 --> ManualReview : [amount > 100]
  C1 --> AutoShip : [amount <= 100]

第四步:组合成一个完整的例子

代码段

stateDiagram-v2
  [*] --> Paid
  
  Paid --> C1 : check_amount

  state C1 <<choice>>
  C1 --> ManualReview : [amount > 100]
  C1 --> AutoShip : [amount <= 100]

  ManualReview --> AutoShip : approved
  AutoShip --> [*]

这个图清晰地展示了,Paid状态之后,流程会根据金额大小,走向两条不同的路径。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐