概述

简单实现

根据 if 和 else 来判断状态,来进行下一步状态的流转

class Worker {

  public $state;// 天气状态

  function __contruct($state) {
      $this->state = $state;
  }

  public oneDay() {
      if ($this->state == "晴天") {
          echo "骑车上班";
      } elseif ($this->state == "雨天") {
          echo "坐车上班";
      }
  }
}

$worker = new Worker("晴天");
$worker->oneDay();

状态模式

通过接口来实现,避免 if 和 else 来判断。跟策略者模式有点像,只是策略者模式更加注重算法的抽象,例如转账有支付宝转账和微信两种;而状态模式强调的是,状态变更对内部方法执行的影响,例如天气是雨天,对交通工具的影响。

interface State {
    handle()
}

class RainState imple State {
    function handle() {
        echo "坐车去上班"
    }
}

class Worker {
    public oneDay($state State) {
        $state->handle();
    }
}

$worker = new Worker();
$worker->oneDay(new RainState());

状态机

状态机的几个节点有:

现态->事件->动作->次态,现态经过某个事件触发后,会变成其他状态。

lbjeb1l8.png

如果下一个状态是确定的,只有一个的话

实现的时候可以通过以下方式:

public function getNextStatus (){
    if (state == "未提交") {
        return "领导审核"
    } else if (state == "未提交") {
        return "Hr审核"
    }
}

或者可以是这样,调用 wetijiao.getNextStatus 就可以获取下一个状态了,避免 if 和 else

// 未提交状态
type WeiTiJiao {

}
function (w *WeiTiJiao) getNextStatus () {
    return "领导审核"
}

由于下个状态经常需要某个事件来决定,例如领导审批同意事件后是 Hr 审批,如果拒绝的时候状态是拒绝,这个时候怎么办

这个时候可以引入双层 map 来实现简单的状态机定义方式,例如:

$status = [
    "领导审核" => [
        "通过" => "Hr审核",
        "拒绝" => "拒绝"
    ]
];

function getNextStatus ($currentStatus,$envent){
    return $status[currentStatus][envent];
}

getNextStatus("领导审核","通过");

状态机还有一个功能,就是触发某个事件后,会执行某个动作,例如审核通过后要会发送邮件,具体实现还不知道怎么弄

GO FSM

fsm 是 finite state machine 的简写,表示是有限状态机。

安装

通过 go get 命令安装

go get github.com/looplab/fsm

简单使用

package main

import (
  "context"
 "fmt"
 "github.com/looplab/fsm"
)

func main() {
    myFsm := fsm.NewFSM(
        "closed", //初始化时候的状态是closed
       fsm.Events{ //事件
            //状态事件的名称   该事件的起始状态Src         该事件的结束状态Dst
         //即:状态事件“开” 表示事物的状态从状态closed到状态open
         {Name: "开", Src: []string{"closed"}, Dst: "open"}, //开事件,状态从closed 变成 open
            {Name: "关", Src: []string{"open"}, Dst: "closed"}, //关事件,状态从closed 变成 open
        },
      //状态事件调用函数,在此称为 时机函数。关键字用'_'隔开,格式是:"调用时机_事件或状态"
     //before表示在该事件或状态发生之前调用该函数,如"before_warn"
     //依此类推,after表示在...之后,enter表示在进入...之时,leave表示在离开...之时。
       fsm.Callbacks{
          //fsm内定义的状态事件函数,关键字指定的是XXX_event和XXX_state
          //表示任一的状态或状态事件
          "before_event": func(_ context.Context, e *fsm.Event) {
               fmt.Println("before_event") // called before all events
           },
          "leave_state": func(_ context.Context, e *fsm.Event) {
                fmt.Println("leave_state") //called before leaving all states
         },
          //根据自定义状态或事件所定义的状态事件函数
          "before_关": func(_ context.Context, e *fsm.Event) {
               fmt.Println("before_关") // 进入当前状态前做什么
         },
          "before_开": func(_ context.Context, e *fsm.Event) {
               fmt.Println("before_开")
           },
      }, //回调
 )
   fmt.Println("初始化的当前状态为:", myFsm.Current())    // 初始状态为closed
  err := myFsm.Event(context.Background(), "开") // 触发开事件
    if err != nil {
     fmt.Println(err)
        return
  }
   fmt.Println("执行了“开”,当前状态为:", myFsm.Current()) // 状态变成open
 err = myFsm.Event(context.Background(), "关")  // 触发关事件
    if err != nil {
     fmt.Println(err)
        return
  }
   fmt.Println("执行了“关”,当前状态为:", myFsm.Current()) // 状态变成closed
}

关于 Callbacks 有:

  1. before_ - called before event named
  2. before_event - called before all events
  3. leave_ - called before leaving
  4. leave_state - called before leaving all states
  5. enter_ - called after entering
  6. enter_state - called after entering all states
  7. after_ - called after event named
  8. after_event - called after all events

There are also two short form versions for the most commonly used callbacks. They are simply the name of the event or state:

  1. - called after entering
  2. - called after event named

If both a shorthand version and a full version is specified it is undefined which version of the callback will end up in the internal map. This is due to the pseudo random nature of Go maps. No checking for multiple keys is currently performed.

参考

  1. https://pkg.go.dev/github.com/looplab/fsm#section-readme
最后修改:2023 年 12 月 30 日
如果觉得我的文章对你有用,请随意赞赏