快捷搜索: 王者荣耀 脱发

用go基于有向图实现一个有限状态机器(FSM)

    构建一个有向图:状态就是节点,状态到状态的事件就是边的类型 一个FSM = FSM的当前状态 + 一个图 事件发生,状态变更:以当前状态为from节点,事件的out边找到的那个顶点就是事件发生后的状态,然后把这个状态作为当前状态 如下图就可以看作成一个FSM(一个图+当前状态): 1、节点(状态)有:Locked、UnLocked 2、边的类型(事件)有:Push、Coin;具体有4条边 3、初始状态是Locked 4、向初始的FSM发送事件Coin,以Locked为from定点,Coin为out边找到的节点就是UnLoked,然后把UnLoked作为当前状态
    代码: package main import ( "fmt" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/multi" ) /* 基于gonum定义节点和边 */ type State struct { Id int64 Value interface{} } type Link struct { Id int64 T, F graph.Node Event Event } func (n State) ID() int64 { return n.Id } func (n State) String() string { return n.Value.(string) } func (l Link) From() graph.Node { return l.F } func (l Link) To() graph.Node { return l.T } func (l Link) ID() int64 { return l.Id } func (l Link) ReversedLine() graph.Line { return Link{F: l.T, T: l.F} } /* 定义FSM */ type Event string var NodeIDCnt = 0 var LineIdCnt = 1 type StateMachine struct { PresentState State g *multi.DirectedGraph } func New() *StateMachine { s := &StateMachine{} s.g = multi.NewDirectedGraph() return s } func (s *StateMachine) InitState(initValue interface{}) State { s.PresentState = s.NewState(initValue) return s.PresentState } func (s *StateMachine) NewState(stateValue interface{}) State { state := State{Id: int64(NodeIDCnt), Value: stateValue} s.g.AddNode(state) NodeIDCnt++ return state } func (s *StateMachine) LinkStates(s1, s2 State, event Event) { s.g.SetLine(Link{F: s1, T: s2, Id: int64(LineIdCnt), Event: event}) LineIdCnt++ } // FireEvent 触发事件 func (s *StateMachine) FireEvent(e Event) error { presentNode := s.PresentState it := s.g.From(presentNode.Id) for it.Next() { to := s.g.Node(it.Node().ID()).(State) line := graph.LinesOf(s.g.Lines(presentNode.Id, to.Id))[0].(Link) if line.Event == e { s.PresentState = to return nil } return fmt.Errorf("没有对应的事件:%s", e) } return nil } // Compute 批量触发处理 func (s *StateMachine) Compute(events []string, printState bool) State { for _, e := range events { previousState := s.PresentState err := s.FireEvent(Event(e)) if err != nil { panic(err) } if printState { fmt.Printf("触发事件[%s]后,状态由[%s]变为了[%s] ", e, previousState, s.PresentState.String()) } } return s.PresentState } func main() { //构造有向图 stateMachine := New() lockedState := stateMachine.InitState("locked") unlockedSate := stateMachine.NewState("unlocked") coinEvent := Event("coin") pushEvent := Event("push") stateMachine.LinkStates(lockedState, unlockedSate, coinEvent) stateMachine.LinkStates(unlockedSate, lockedState, pushEvent) stateMachine.LinkStates(lockedState, lockedState, pushEvent) stateMachine.LinkStates(unlockedSate, unlockedSate, coinEvent) //触发事件 fmt.Printf("初始状态: %s ", stateMachine.PresentState.String()) events := []string{"coin", "push"} stateMachine.Compute(events, true) fmt.Printf("最终状态: %s ", stateMachine.PresentState.String()) } 输出结果:

初始状态: locked 触发事件[coin]后,状态由[locked]变为了[unlocked] 触发事件[push]后,状态由[unlocked]变为了[locked] 最终状态: locked

    参考资料:
经验分享 程序员 微信小程序 职场和发展