赞
踩
目录
目录
有限状态机,英⽂翻译是 Finite State Machine,缩写为 FSM,简称为状态机。
状态机不是指一台实际机器,而是指一个数学模型。说白了,一般就是指一张状态转换图。
已订单交易为例:
下面来给出状态机的四大概念。
将上面业务流程翻译成骨架代码:
-
- type State int64
-
- const StateWaitingPayment State = 1 //等待支付
- const StateWaitingShip State = 2 //支付成功待发货
-
- // 订单状态机
- type LeaseStateMachine struct {
- State State //订单状态
- }
-
- // 订单支付成功
- func (p *LeaseStateMachine) EventPaySuccess() {
- //todo
- }
-
- // 取消了订单
- func (p *LeaseStateMachine) EventCancelOrder() {
- //todo
- }
-
- // 商家发货
- func (p *LeaseStateMachine) EventShipped() {
- //todo
- }
-
- // 确认收货
- func (p *LeaseStateMachine) EventConfirmReceipt() {
- //todo
- }
最简单直接的实现⽅式是,参照状态转移 图,将每⼀个状态转移,直译成代码。这样编写的代码会包含⼤量的 if-else 或 switch-case 分⽀判断逻辑。
- type State int64
-
- const StateWaitingPayment State = 1 //等待支付
- const StateWaitingShip State = 2 //支付成功待发货
- const StateWaitingShipped State = 3 //发货成功
- const StateWaitingOrderSuccess State = 4 //订单结束
- const StateWaitingOrderCancel State = 5 //订单取消
-
- // 租赁订单状态机
- type LeaseStateMachine struct {
- State State //订单状态
- }
-
- // 订单支付成功
- func (p *LeaseStateMachine) EventPaySuccess() {
- if p.State == StateWaitingPayment {
- p.State = StateWaitingShip
- }
- }
-
- // 取消了订单
- func (p *LeaseStateMachine) EventCancelOrder() {
- if p.State == StateWaitingShip ||
- p.State == StateWaitingPayment {
- p.State = StateWaitingOrderCancel
- }
- }
-
- // 商家发货
- func (p *LeaseStateMachine) EventShipped() {
- if p.State == StateWaitingShip {
- p.State = StateWaitingShipped
- }
- }
-
- // 确认收货
- func (p *LeaseStateMachine) EventConfirmReceipt() {
- if p.State == StateWaitingShipped {
- p.State = StateWaitingOrderSuccess
- }
- }
除了⽤状态转移图来表示之外,状态机还可以⽤⼆维表来表示;将上面的状态图转换成二维表如下
当前状态/事件 | E支付成功 | E发货 | E取消订单 | E确认收货 |
---|---|---|---|---|
等待支付 | 支付成功待发货 | / | / | / |
支付成功待发货 | / | 发货成功 | 订单取消 | / |
已发货 | / | / | / | 订单结束 |
订单结束 | / | / | / | / |
订单取消 | / | / | / | / |
使用查表表修改上述代码:
-
- type State int64
-
- const StateWaitingPayment State = 1 //等待支付
- const StateWaitingShip State = 2 //支付成功待发货
- const StateWaitingShipped State = 3 //发货成功
- const StateWaitingOrderSuccess State = 4 //订单结束
- const StateWaitingOrderCancel State = 5 //订单取消
-
- type Event int64
-
- const (
- EventPay Event = 1 //支付事件
- EventShip Event = 2 //发货 事件
- EventCancel Event = 3 //取消订单 事件
- EventConfirmReceipt Event = 4 //确认收货
- )
-
- // 状态二维表配置
- var StateTable map[State]map[Event]State = map[State]map[Event]State{
- StateWaitingPayment: {
- EventPay: StateWaitingShip, //待支付订单 ,支付事件 => 已支付
- },
- StateWaitingShip: {
- EventShip: StateWaitingShipped,
- EventCancel: StateWaitingOrderCancel,
- },
- //.......
- }
-
- // 租赁订单状态机
- type LeaseStateMachine struct {
- State State //订单状态
-
- }
-
- // 订单支付成功
- func (p *LeaseStateMachine) EventPaySuccess() {
- p.ExecEventConfirmReceipt(EventPay)
- }
-
- // 取消了订单
- func (p *LeaseStateMachine) EventCancelOrder() {
- p.ExecEventConfirmReceipt(EventCancel)
- }
-
- // 商家发货
- func (p *LeaseStateMachine) EventShipped() {
- p.ExecEventConfirmReceipt(EventShip)
- }
-
- // 确认收货
- func (p *LeaseStateMachine) EventConfirmReceipt() {
-
- p.ExecEventConfirmReceipt(EventConfirmReceipt)
- }
-
- // 执行事件
- func (p *LeaseStateMachine) ExecEventConfirmReceipt(event Event) {
- EventNewStateTable, ok := StateTable[p.State]
- if ok {
- newState, ok := EventNewStateTable[event]
- if ok {
- p.State = newState
- }
- }
- }
在查表法的代码实现中,事件触发的动作只是简单状态变换,所以⽤⼀个 int 类型 的⼆维数组 actionTable 就能表示。但是,如果要执⾏ 动作并⾮这么简单,⽽是⼀系列复杂的逻辑操作(⽐如加减积分、写数据库,还有可能发 送消息通知等等),我们就没法⽤如此简单的⼆维数组来表示了。
状态模式通过将事件触发的状态转移和动作执⾏,拆分到不同的状态类中,来避免分⽀判断
1.定义interface 所有事件
- type ILeaseState interface {
- //定义事件
- EventPay() //支付事件
- EventShip() //发货事件
- EventCancel() //取消订单事件
- EventConfirmReceipt() //确认收货事件
- }
-
2.状态类实现 事件对应的action
将事件对饮的代码逻辑被分散到各个状态类中。
- //==================================================================
- // 待支付状态
- type StateWaitingPaymentImp struct{}
-
- // 订单支付成功
- func (p *StateWaitingPaymentImp) EventPay() {
- //todo 更新订单状态
- }
-
- // 发货
- func (p *StateWaitingPaymentImp) EventShip() {
- //不做处理
- }
-
- // 取消
- func (p *StateWaitingPaymentImp) EventCancel() {
- //todo 取消
- }
-
- // 确认收货事件
- func (p *StateWaitingPaymentImp) EventConfirmReceipt() {
- //不做处理
- }
- //==================================================================
- // 支付成功 状态
- type StateWaitingShipImp struct{}
-
- // 订单支付成功
- func (p *StateWaitingShipImp) EventPay() {
- //不做任何处理
- }
-
- // 发货
- func (p *StateWaitingShipImp) EventShip() {
- //更新订单未发货
- }
-
- // 取消
- func (p *StateWaitingShipImp) EventCancel() {
- //更新订单未发货
- }
-
- // 确认收货事件
- func (p *StateWaitingShipImp) EventConfirmReceipt() {
- //不做处理
- }
- //===============================================================
- //........其他状态对应的事件
实现方法 | 优点 | 缺点 |
---|---|---|
分支逻辑 |
|
|
查表法
|
|
|
状态模式 |
|
|
像电商下单这种状态并不多,状态转移也⽐较简单,但事件触发执⾏的动作包含的业务逻辑可能会⽐较复杂,更加推荐使⽤状态模式来实现。
像游戏⽐较复杂的状态机,包含的状态⽐较多,优先推荐使⽤查表法;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。