FSM(Finite-State Machine)
  1. package main
  2. import (
  3. "errors"
  4. "fmt"
  5. "reflect"
  6. )
  7. type State interface {
  8. //get name of state.
  9. Name() string
  10. //是否允许同态转移.
  11. EnableSameTansit() bool
  12. //begin
  13. OnBegin()
  14. //end
  15. OnEnd()
  16. //if transit.
  17. CanTransitTo(name string) bool
  18. }
  19. func StateName(s State) string {
  20. if nil == s {
  21. return "none"
  22. }
  23. return reflect.TypeOf(s).Elem().Name()
  24. }
  25. type StateInfo struct {
  26. name string
  27. }
  28. func (si *StateInfo) Name() string {
  29. return si.name
  30. }
  31. func (si *StateInfo) setName(name string) {
  32. si.name = name
  33. }
  34. func (si *StateInfo) EnableSameTansit() bool {
  35. return false
  36. }
  37. func (si *StateInfo) OnBegin() {
  38. }
  39. func (si *StateInfo) OnEnd() {
  40. }
  41. func (si *StateInfo) CanTransitTo(name string) bool {
  42. return true
  43. }
  44. //-----------------------manager.
  45. //transit State.
  46. var ErrStateNotFound = errors.New("state not found.")
  47. var ErrForbidSameStateTransit = errors.New("forbid same state transit")
  48. var ErrCannotTransitToState = errors.New("cannot transit to state")
  49. type StateManager struct {
  50. stateByName map[string]State
  51. OnChange func(from, to State)
  52. currenteState State
  53. }
  54. func (sm *StateManager) Get(name string) State {
  55. if s, ok := sm.stateByName[name]; ok {
  56. return s
  57. }
  58. return nil
  59. }
  60. func (sm *StateManager) Add(state State) {
  61. name := StateName(state)
  62. if nil != sm.Get(name) {
  63. panic("duplicate state:" + name)
  64. }
  65. state.(interface {
  66. setName(name string)
  67. }).setName(name)
  68. sm.stateByName[name] = state
  69. }
  70. func NewStateManager() *StateManager {
  71. return &StateManager{
  72. stateByName: make(map[string]State),
  73. }
  74. }
  75. func (sm *StateManager) CurrentState() State {
  76. return sm.currenteState
  77. }
  78. func (sm *StateManager) CanCurrTranistTo(name string) bool {
  79. if nil == sm.currenteState {
  80. return true
  81. }
  82. if sm.currenteState.Name() == name && !sm.currenteState.EnableSameTansit() {
  83. return false
  84. }
  85. return sm.currenteState.CanTransitTo(name)
  86. }
  87. func (sm *StateManager) Transit(name string) error {
  88. //get the next state.
  89. nextstate := sm.stateByName[name]
  90. if nil == nextstate {
  91. return ErrStateNotFound
  92. }
  93. if nil != sm.currenteState {
  94. if name == sm.currenteState.Name() && !sm.currenteState.EnableSameTansit() {
  95. return ErrForbidSameStateTransit
  96. }
  97. if !sm.currenteState.CanTransitTo(name) {
  98. return ErrCannotTransitToState
  99. }
  100. //current state end.
  101. sm.currenteState.OnEnd()
  102. }
  103. prestate := sm.currenteState
  104. sm.currenteState = nextstate
  105. //new state begin.
  106. sm.currenteState.OnBegin()
  107. //callback Change.
  108. if nil != sm.OnChange {
  109. sm.OnChange(prestate, sm.currenteState)
  110. }
  111. return nil
  112. }
  113. //----------------------
  114. //-----------------------------------------------State....
  115. // 闲置状态
  116. type IdleState struct {
  117. StateInfo // 使用StateInfo实现基础接口
  118. }
  119. // 重新实现状态开始
  120. func (i *IdleState) OnBegin() {
  121. fmt.Println("IdleState begin")
  122. }
  123. // 重新实现状态结束
  124. func (i *IdleState) OnEnd() {
  125. fmt.Println("IdleState end")
  126. }
  127. // 移动状态
  128. type MoveState struct {
  129. StateInfo
  130. }
  131. func (m *MoveState) OnBegin() {
  132. fmt.Println("MoveState begin")
  133. }
  134. // 允许移动状态互相转换
  135. func (m *MoveState) EnableSameTransit() bool {
  136. return true
  137. }
  138. // 跳跃状态
  139. type JumpState struct {
  140. StateInfo
  141. }
  142. func (j *JumpState) OnBegin() {
  143. fmt.Println("JumpState begin")
  144. }
  145. // 跳跃状态不能转移到移动状态
  146. func (j *JumpState) CanTransitTo(name string) bool {
  147. return name != "MoveState"
  148. }
  149. func main() {
  150. //create a Stata Manager.
  151. stateManager := NewStateManager()
  152. stateManager.OnChange = func(from, to State) {
  153. fmt.Printf("state changed, from %s to %s.\n", StateName(from), StateName(to))
  154. }
  155. stateManager.Add(new(IdleState))
  156. stateManager.Add(new(JumpState))
  157. stateManager.Add(new(MoveState))
  158. // 在不同状态间转移
  159. transitAndReport(stateManager, "IdleState")
  160. transitAndReport(stateManager, "MoveState")
  161. transitAndReport(stateManager, "MoveState")
  162. transitAndReport(stateManager, "JumpState")
  163. transitAndReport(stateManager, "JumpState")
  164. transitAndReport(stateManager, "IdleState")
  165. }
  166. // 封装转移状态和输出日志
  167. func transitAndReport(sm *StateManager, target string) {
  168. if err := sm.Transit(target); err != nil {
  169. fmt.Printf("FAILED! %s --> %s, %s\n\n", sm.CurrentState().Name(), target, err.Error())
  170. }
  171. }

Output:

  1. PS C:\Users\Administrator\Desktop\Test\go\goTest> go run .\finiteStateMachin.go
  2. IdleState begin
  3. state changed, from none to IdleState.
  4. IdleState end
  5. MoveState begin
  6. state changed, from IdleState to MoveState.
  7. FAILED! MoveState --> MoveState, forbid same state transit
  8. JumpState begin
  9. state changed, from MoveState to JumpState.
  10. FAILED! JumpState --> JumpState, forbid same state transit
  11. IdleState begin
  12. state changed, from JumpState to IdleState.
  13. PS C:\Users\Administrator\Desktop\Test\go\goTest>

关于有限状态机的设计,
首先分解问题:状态机包括状态和状态管理,故可以分为两部分来进行抽象:State和Manager;各个State之间是存在不同的转换关系的,而这些关系由谁来掌握规则?State?Manager?从阔扩展性的方向来看,转换规则是作为一个State的属性存在,所以自然由State自己实现,降低了State和Manager的耦合,也就增加了状态的可扩展性。
所有State实例实现两个接口:State和interface {
setName(name string)
}匿名接口。
其实大多时候,设计的目的在于提高效率,美丽的设计具有低耦合性。