FSM有限状态机golang实战

FSM有限状态机

FSM:finite state machion,有限状态机。

两种实现方式:

简单switch case

适用于简单的状态机

int stateMachion(int event)
{
	switch(curSate)
	{
    case sleeping:
    	switch(event)
    	{
    		case hungary:
            	eatIt();
            	curState = eating;
            ......
    	}
    	......
	}
}

状态对象化

状态机要素:

  • 初始状态

  • 当前状态

  • 状态迁移,上一个状态退出,下一个状态进入。

状态机运行的3个对象:

  • 状态类

    将每个状态抽象出状态类,每个状态都有进入、退出函数,另外加一个状态中执行的函数。

  • 状态机类

    表示状态机的参数,当前状态、提供状态迁移辅助函数;

  • 外部驱动

    外部驱动状态机切换状态,可以是直接调用状态机切换状态,也可以是事件驱动,状态机处理事件,自行切换状态。

执行流:

外部驱动 => 状态机 => 状态。

状态类

struct state {
	enter();
	exit();
	stay();
}

状态机类

struct stateMachion{
	/*当前状态*/
	curState();
	/*状态迁移函数*/
	switchState();
}

外部驱动

  • 直接驱动

适用于switch case情况,直接将状态迁移条件传入即可。

stateMachion(hungary);
stateMachion(sleepy);
  • 事件驱动

状态机中增加事件处理函数,执行每个状态的事件处理函数。

事件驱动状态机

事件驱动状态机的状态推进有事件推动,不同状态下对应不同事件处理函数.

状态类

增加每个状态事件处理函数。

struct state {
	enter();
	exit();
	stay();
	eventHandler();
}

状态机类

添加事件处理总入口

struct stateMachion {
	curState();
	switchState();	
	eventHandler();
}

实战

事件驱动状态机。以一个人一天的生活状态为例。

状态轮转

FSM有限状态机golang实战_第1张图片

数据结构

使用go语言编程

1)状态定义

type STATE_TYPE int

/*状态*/
const (
	STATE_SLEEPING STATE_TYPE = iota
	STATE_EATING
	STATE_GAMING
	STATE_END
)

2)事件定义

type EVENT_TYPE int

/*事件*/
const (
	EVENT_SLEEPY EVENT_TYPE = iota
	EVENT_HUNGARY
	EVENT_BORING
	EVENT_END
)

3)状态类

/*状态类*/
type STATE interface {
	enter()
	exit()
	stay()
	eventHandler(*STATE_MACHION, EVENT_TYPE)
}

4)状态机类

type STATE_MACHION struct {
	curStateType STATE_TYPE
	statePool    map[STATE_TYPE]STATE
	
	/*初始状态*/
	initState()
	/*添加状态*/
	addState()
	/*切换状态函数*/
	switchToState()
}

框图

FSM有限状态机golang实战_第2张图片

代码

package main

import (
	"fmt"
	"strings"
	"time"
)

type STATE_TYPE int

/*状态*/
const (
	STATE_SLEEPING STATE_TYPE = iota
	STATE_EATING
	STATE_GAMING
	STATE_END
)

type EVENT_TYPE int

/*事件*/
const (
	EVENT_SLEEPY EVENT_TYPE = iota
	EVENT_HUNGARY
	EVENT_BORING
	EVENT_END
)

/*状态类*/
type STATE interface {
	enter()
	exit()
	stay()
	eventHandler(*STATE_MACHION, EVENT_TYPE)
}

/*sleeping状态*/
type stateSleep struct {
	sleepState bool
}

func (state *stateSleep) enter() {
	fmt.Println("okay, i'm to sleep, touch my bed!")
	state.sleepState = true
	state.stay()
}

func (state *stateSleep) exit() {
	fmt.Println("i'm wakely, leave my bed!")
	state.sleepState = false
}

func (state *stateSleep) stay() {
	go func() {
		for {
			if state.sleepState == false {
				break
			}
			fmt.Println("heng heng heng....")
			time.Sleep(5 * time.Second)
		}
	}()
}

func (state *stateSleep) eventHandler(sm *STATE_MACHION, event EVENT_TYPE) {
	switch event {
	case EVENT_HUNGARY:
		sm.switchToState(STATE_EATING)
		break
	case EVENT_BORING:
		sm.switchToState(STATE_GAMING)
		break
	}
}

/*eating状态*/
type stateEating struct {
	eatingState bool
}

func (state *stateEating) enter() {
	fmt.Println("okay, i'm to eat, give my bowl!")
	state.eatingState = true
	state.stay()
}

func (state *stateEating) exit() {
	fmt.Println("eat end,  drow my bowl!")
	state.eatingState = false
}

func (state *stateEating) stay() {
	go func() {
		for {
			if state.eatingState == false {
				break
			}
			fmt.Println("kuangci kuangci kuangci....")
			time.Sleep(5 * time.Second)
		}
	}()
}

func (state *stateEating) eventHandler(sm *STATE_MACHION, event EVENT_TYPE) {
	switch event {
	case EVENT_SLEEPY:
		sm.switchToState(STATE_SLEEPING)
		break
	case EVENT_BORING:
		sm.switchToState(STATE_GAMING)
		break
	}
}

/*gaming状态*/
type stateGaming struct {
	gamingState bool
}

func (state *stateGaming) enter() {
	fmt.Println("start game, take my switch!")
	state.gamingState = true
	state.stay()
}

func (state *stateGaming) exit() {
	fmt.Println("game over, destory the f*ck swith!")
	state.gamingState = false
}

func (state *stateGaming) stay() {
	go func() {
		for {
			if state.gamingState == false {
				break
			}
			fmt.Println("nice... f*ck.... ")
			time.Sleep(5 * time.Second)
		}
	}()
}

func (state *stateGaming) eventHandler(sm *STATE_MACHION, event EVENT_TYPE) {
	switch event {
	case EVENT_SLEEPY:
		sm.switchToState(STATE_SLEEPING)
		break
	case EVENT_HUNGARY:
		sm.switchToState(STATE_EATING)
		break
	}
}

/*状态机类*/
type STATE_MACHION struct {
	curStateType STATE_TYPE
	statePool    map[STATE_TYPE]STATE
}

func (sm *STATE_MACHION) addState(stateType STATE_TYPE, state STATE) {
	sm.statePool[stateType] = state
}

func (sm *STATE_MACHION) initState(stateType STATE_TYPE) {
	sm.curStateType = stateType
	sm.statePool[stateType].enter()
}

func (sm *STATE_MACHION) switchToState(stateType STATE_TYPE) {
	sm.statePool[sm.curStateType].exit()
	sm.statePool[stateType].enter()
	sm.curStateType = stateType
}

func (sm *STATE_MACHION) eventHandler(event EVENT_TYPE) {
	sm.statePool[sm.curStateType].eventHandler(sm, event)
}

func main() {
	/*构造对象*/
	staEat := stateEating{}
	staSleep := stateSleep{}
	staGame := stateGaming{}

	sm := STATE_MACHION{}

	/*添加状态*/
	sm.statePool = make(map[STATE_TYPE]STATE)
	sm.addState(STATE_SLEEPING, &staSleep)
	sm.addState(STATE_EATING, &staEat)
	sm.addState(STATE_GAMING, &staGame)

	sm.initState(STATE_SLEEPING)
	var inputChr string
	for {
		inputChr = ""
		fmt.Scanln(&inputChr)
		fmt.Println(inputChr)
		if strings.Compare(inputChr, "sleep") == 0 {
			sm.eventHandler(EVENT_SLEEPY)
		} else if strings.Compare(inputChr, "hungary") == 0 {
			sm.eventHandler(EVENT_HUNGARY)
		} else if strings.Compare(inputChr, "boring") == 0 {
			sm.eventHandler(EVENT_BORING)
		}
	}
	fmt.Println(EVENT_BORING)
}

TODO

为了可以动态添加状态而不修改原来的代码,可以加一个“由哪个状态可以切到我” 的处理函数,前面的eventhandler都是“我可以切到那些状态”。这样新加状态可以定义我能切到谁,谁可以切到我,原始的状态不需要修改。在事件处理时先匹配"我能切到谁",然后再遍历所有状态的”谁能切到我“。

你可能感兴趣的:(golang学习笔记,python,开发语言,后端,golang)