使用FSM进行复杂订单状态管理(1)

tech

This article was last updated on <span id="expire-date"></span> days ago, the information described in the article may be outdated.

在商城类项目过程的开发过程中我们常常会遇到订单状态的管理问题,当所涉及到的订单状态不多时,我们通常可以对每一种状态设置标志字符串,通过简单的判断来进行状态管理。

例如,假设我们的系统中仅涉及两个状态:订单被创建、订单完成,此时我们可以写下如下的代码:

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
from collections import namedtuple

# 使用 namedtuple 创建一个简单的状态类
Status = namdtuple("Status", ("flag", "description"))

# 创建需要的状态
CREATED = Status(flag="CREATED", description="订单被创建")
COMPLETED = Status(flag="COMPLETED", description="订单完成")

# 程序逻辑部分
@yourapp.route("/order/<string:orderid>/<string:action>", methods=["POST"])
def order_handler(orderid: str, action: str) -> Tuple[str, str]:
"""
这里 action 是从前端传入的事件标志字符串
返回状态标识符以及状态描述
"""

if action == "USER_ORDER":
... # 创建订单动作
if action == "USER_PAID":
order = get_order_byid(orderid)
if order.status == CREATED:
... # 支付后动作
order.status = COMPLETED

return order.status.flag, order.status.description

可以看到,这个系统的管理仅仅涉及到两个状态的转移,就已经较为繁琐了,并且将字符串直接写死在程序中也是非常不好的实现;这样写出的程序也很难扩展。

那么当状态较多,问题较为复杂时,我们应该如何处理呢?

什么是FSM

众所周知,FSM (Flying Spaghetti Monsterism) 是飞天面条神教的简称

FSM (Finite-State-Machine) 是有限状态机的简称,有限状态机定义为一个五元组:$(Q, \Omega, \delta, q_0, F)$,其中:

  • $Q$ - 状态的有限集合
  • $\Omega$ - 接受符号的有限非空集合
  • $\delta$ - 转移动作的集合
  • $q_0$ - 初始状态
  • $F$ - 状态转移表

根据定义,在有限状态机模型里,我们需要确定初始状态和中止状态;而每一个状态在发生一种特定动作的情况下有且仅有一中目标状态可以转移;同时,在状态转移时会计算转移函数的值。

问题分析

那么,如果我们将订单状态管理的问题抽象出来,可以发现订单的状态的管理需要以下几个步骤:

  1. 获取到当前的状态
  2. 判断当前的状态是否可以进行指定的动作(例如订单已经完成,就不能够重新支付)
  3. 根据当前的状态和给定的动作确定要转移之后的动作(例如当前是订单创建状态,在_支付_这个动作之后需要转移至完成状态)

我们会发现,如果将订单状态类比为FSM中的状态集合,发生的事件类比为FSM中的输入符号集合,事件执行的转移函数类比为FSM中的转移函数,我们可以发现,这种问题如果引入有限状态机的模型去解决,会方便很多。

下面一篇文章,我们将实现一个简单的有限状态机。

Author: 桂小方

Permalink: https://init.blog/1831/

文章许可协议:

如果你觉得文章对你有帮助,可以 支持我

Comments