有限狀態(tài)機(Finite-state machine, 簡寫FSM)又可以稱作有限狀態(tài)自動機。它必須是可以附著在某種事物上的革屠,且該事物的狀態(tài)是有限的,通過某些觸發(fā)事件,會讓其狀態(tài)發(fā)生轉換扁远。為此,有限狀態(tài)機就是描述這些有限的狀態(tài)和觸發(fā)事件及轉換行為的數(shù)學模型刻像。
有限狀態(tài)機組成
有限狀態(tài)機有兩個必要的特點畅买,一是離散的,二是有限的绎速∑せ瘢基于這兩點,現(xiàn)實世界上絕大多數(shù)事物因為復雜的狀態(tài)而無法用有限狀態(tài)機表示纹冤。
而描述事物的有限狀態(tài)機模型的元素由以下組成:
- 狀態(tài)(State):事物的狀態(tài)洒宝,包括初始狀態(tài)和所有事件觸發(fā)后的狀態(tài)
- 事件(Event):觸發(fā)狀態(tài)變化或者保持原狀態(tài)的事件
- 行為或轉換(Action/Transition):執(zhí)行狀態(tài)轉換的過程
- 檢測器(Guard):檢測某種狀態(tài)要轉換成另一種狀態(tài)的條件是否滿足
應用領域
除了剛剛介紹的數(shù)學模型應用,有限狀態(tài)機在許多不同領域都有重要應用萌京,包括電氣工程雁歌、語言學、計算機科學知残、哲學靠瞎、生物學、數(shù)學和邏輯學。有限狀態(tài)機歸屬于自動機理論乏盐,下面的自動機理論的領域分層圖中就可以看出佳窑,越是外層的概念越復雜。
有限狀態(tài)機的舉例
我們就拿身邊最經典的電風扇來舉例父能。假如電風扇有4個按鈕神凑,分別是關、1檔何吝、2檔和3檔溉委,關按鈕負責關閉電風扇,也就是停止電風扇的轉動爱榕;而1瓣喊、2、3檔都可以讓電風扇開啟黔酥,且風扇轉動的速度不一樣藻三,產生的風力也不一樣。
這時我們判斷出風扇的4個狀態(tài)絮爷,分別是關閉(poweroff)趴酣、1檔(1st gear)、2檔(2nd gear)坑夯、3檔(3rd gear)岖寞。而4個按鈕的按下操作可以影響電風扇的狀態(tài)。下面用狀態(tài)圖來說明:
如果看不清楚柜蜈,還有狀態(tài)轉移表
為了更直觀的讓程序員了解FSM具體有什么用仗谆,我將電風扇的有限狀態(tài)機用程序來演示。
Go語言下的有限狀態(tài)機
一共2個文件淑履,fsm.go是有限狀態(tài)機的抽象定義隶垮,main.go里是有限狀態(tài)機在電風扇上的具體狀態(tài)呈現(xiàn),代碼如下:
// fsm.go
package main
import (
"fmt"
"sync"
)
type FSMState string // 狀態(tài)
type FSMEvent string // 事件
type FSMHandler func() FSMState // 處理方法秘噪,并返回新的狀態(tài)
// 有限狀態(tài)機
type FSM struct {
mu sync.Mutex // 排他鎖
state FSMState // 當前狀態(tài)
handlers map[FSMState]map[FSMEvent]FSMHandler // 處理地圖集狸吞,每一個狀態(tài)都可以出發(fā)有限個事件,執(zhí)行有限個處理
}
// 獲取當前狀態(tài)
func (f *FSM) getState() FSMState {
return f.state
}
// 設置當前狀態(tài)
func (f *FSM) setState(newState FSMState) {
f.state = newState
}
// 某狀態(tài)添加事件處理方法
func (f *FSM) AddHandler(state FSMState, event FSMEvent, handler FSMHandler) *FSM {
if _, ok := f.handlers[state]; !ok {
f.handlers[state] = make(map[FSMEvent]FSMHandler)
}
if _, ok := f.handlers[state][event]; ok {
fmt.Printf("[警告] 狀態(tài)(%s)事件(%s)已定義過", state, event)
}
f.handlers[state][event] = handler
return f
}
// 事件處理
func (f *FSM) Call(event FSMEvent) FSMState {
f.mu.Lock()
defer f.mu.Unlock()
events := f.handlers[f.getState()]
if events == nil {
return f.getState()
}
if fn, ok := events[event]; ok {
oldState := f.getState()
f.setState(fn())
newState := f.getState()
fmt.Println("狀態(tài)從 [", oldState, "] 變成 [", newState, "]")
}
return f.getState()
}
// 實例化FSM
func NewFSM(initState FSMState) *FSM {
return &FSM{
state: initState,
handlers: make(map[FSMState]map[FSMEvent]FSMHandler),
}
}
// main.go
package main
import (
"fmt"
)
var (
Poweroff = FSMState("關閉")
FirstGear = FSMState("1檔")
SecondGear = FSMState("2檔")
ThirdGear = FSMState("3檔")
PowerOffEvent = FSMEvent("按下關閉按鈕")
FirstGearEvent = FSMEvent("按下1檔按鈕")
SecondGearEvent = FSMEvent("按下2檔按鈕")
ThirdGearEvent = FSMEvent("按下3檔按鈕")
PowerOffHandler = FSMHandler(func() FSMState {
fmt.Println("電風扇已關閉")
return Poweroff
})
FirstGearHandler = FSMHandler(func() FSMState {
fmt.Println("電風扇開啟1檔指煎,微風徐來蹋偏!")
return FirstGear
})
SecondGearHandler = FSMHandler(func() FSMState {
fmt.Println("電風扇開啟2檔,涼颼颼至壤!")
return SecondGear
})
ThirdGearHandler = FSMHandler(func() FSMState {
fmt.Println("電風扇開啟3檔威始,發(fā)型被吹亂了!")
return ThirdGear
})
)
// 電風扇
type ElectricFan struct {
*FSM
}
// 實例化電風扇
func NewElectricFan(initState FSMState) *ElectricFan {
return &ElectricFan{
FSM: NewFSM(initState),
}
}
// 入口函數(shù)
func main() {
efan := NewElectricFan(Poweroff) // 初始狀態(tài)是關閉的
// 關閉狀態(tài)
efan.AddHandler(Poweroff, PowerOffEvent, PowerOffHandler)
efan.AddHandler(Poweroff, FirstGearEvent, FirstGearHandler)
efan.AddHandler(Poweroff, SecondGearEvent, SecondGearHandler)
efan.AddHandler(Poweroff, ThirdGearEvent, ThirdGearHandler)
// 1檔狀態(tài)
efan.AddHandler(FirstGear, PowerOffEvent, PowerOffHandler)
efan.AddHandler(FirstGear, FirstGearEvent, FirstGearHandler)
efan.AddHandler(FirstGear, SecondGearEvent, SecondGearHandler)
efan.AddHandler(FirstGear, ThirdGearEvent, ThirdGearHandler)
// 2檔狀態(tài)
efan.AddHandler(SecondGear, PowerOffEvent, PowerOffHandler)
efan.AddHandler(SecondGear, FirstGearEvent, FirstGearHandler)
efan.AddHandler(SecondGear, SecondGearEvent, SecondGearHandler)
efan.AddHandler(SecondGear, ThirdGearEvent, ThirdGearHandler)
// 3檔狀態(tài)
efan.AddHandler(ThirdGear, PowerOffEvent, PowerOffHandler)
efan.AddHandler(ThirdGear, FirstGearEvent, FirstGearHandler)
efan.AddHandler(ThirdGear, SecondGearEvent, SecondGearHandler)
efan.AddHandler(ThirdGear, ThirdGearEvent, ThirdGearHandler)
// 開始測試狀態(tài)變化
efan.Call(ThirdGearEvent) // 按下3檔按鈕
efan.Call(FirstGearEvent) // 按下1檔按鈕
efan.Call(PowerOffEvent) // 按下關閉按鈕
efan.Call(SecondGearEvent) // 按下2檔按鈕
efan.Call(PowerOffEvent) // 按下關閉按鈕
}
執(zhí)行后返回:
電風扇開啟3檔像街,發(fā)型被吹亂了黎棠!
狀態(tài)從 [ 關閉 ] 變成 [ 3檔 ]
電風扇開啟1檔晋渺,微風徐來!
狀態(tài)從 [ 3檔 ] 變成 [ 1檔 ]
電風扇已關閉
狀態(tài)從 [ 1檔 ] 變成 [ 關閉 ]
電風扇開啟2檔脓斩,涼颼颼木西!
狀態(tài)從 [ 關閉 ] 變成 [ 2檔 ]
電風扇已關閉
狀態(tài)從 [ 2檔 ] 變成 [ 關閉 ]