golang有限状态机实现与管理插件库fsm的使用
Golang有限状态机实现与管理插件库fsm的使用
简介
fsm是一个Golang包,允许你在Go代码中添加有限状态机(FSM)。它比github.com/looplab/fsm性能更高,内存分配更少。
基本用法
定义状态和事件
首先定义状态和事件作为int常量:
const (
StateFoo fsm.State = iota
StateBar
)
const (
EventFoo fsm.Event = iota
EventBar
)
创建状态机和定义转换
f := fsm.New(StateFoo) // 初始状态为StateFoo
// 定义从StateFoo到StateBar的转换,当EventFoo事件发生时
f.Transition(
fsm.On(EventFoo), fsm.Src(StateFoo),
fsm.Dst(StateBar),
)
自定义检查和操作
f.Transition(
fsm.Src(StateFoo), fsm.Check(func() bool {
// 检查某些条件
return true // 返回true允许转换
}),
fsm.Call(func() {
// 转换时执行的操作
}),
)
多次触发事件转换
// 当EventFoo事件第二次发生时才会触发转换
f.Transition(
fsm.On(EventFoo), fsm.Src(StateFoo), fsm.Times(2),
fsm.Dst(StateBar),
)
状态进入和退出回调
// 进入特定状态时的回调
f.EnterState(StateFoo, func() {
// 进入StateFoo时执行
})
// 进入任何状态时的回调
f.Enter(func(state fsm.State) {
// 进入任何状态时执行
})
// 退出特定状态时的回调
f.ExitState(StateFoo, func() {
// 退出StateFoo时执行
})
// 退出任何状态时的回调
f.Exit(func(state fsm.State) {
// 退出任何状态时执行
})
完整示例
package main
import (
"fmt"
"github.com/cocoonspace/fsm"
)
// 定义状态
const (
StateIdle fsm.State = iota
StateWorking
StateDone
)
// 定义事件
const (
EventStart fsm.Event = iota
EventFinish
EventReset
)
func main() {
// 创建状态机,初始状态为Idle
f := fsm.New(StateIdle)
// 定义状态转换
f.Transition(
fsm.On(EventStart), fsm.Src(StateIdle),
fsm.Dst(StateWorking),
)
f.Transition(
fsm.On(EventFinish), fsm.Src(StateWorking),
fsm.Dst(StateDone),
)
f.Transition(
fsm.On(EventReset), fsm.Src(StateDone),
fsm.Dst(StateIdle),
)
// 添加状态进入回调
f.EnterState(StateWorking, func() {
fmt.Println("开始工作...")
})
f.EnterState(StateDone, func() {
fmt.Println("工作完成!")
})
// 触发事件
fmt.Println("当前状态:", f.Current())
f.Event(EventStart) // 从Idle -> Working
fmt.Println("当前状态:", f.Current())
f.Event(EventFinish) // 从Working -> Done
fmt.Println("当前状态:", f.Current())
f.Event(EventReset) // 从Done -> Idle
fmt.Println("当前状态:", f.Current())
}
性能
fsm包比github.com/looplab/fsm性能更高:
BenchmarkCocoonSpaceFSM-12 29371851 40.32 ns/op 0 B/op 0 allocs/op
BenchmarkLooplabFSM-12 2438946 487.8 ns/op 320 B/op 4 allocs/op
(基准测试数据针对两次执行转换)
安装
go get github.com/cocoonspace/fsm
贡献指南
欢迎贡献,只要:
- 包含单元测试和注释
- 不使用外部包
许可证
MIT - 参见LICENSE文件
更多关于golang有限状态机实现与管理插件库fsm的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang有限状态机实现与管理插件库fsm的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang有限状态机实现与fsm库使用指南
有限状态机(FSM)是编程中常用的设计模式,用于管理对象的状态转换。下面我将介绍如何在Golang中实现FSM以及使用fsm插件库。
基本有限状态机实现
首先我们来看一个简单的FSM实现:
package main
import "fmt"
// 定义状态类型
type State string
// 定义状态常量
const (
StateIdle State = "idle"
StateRunning State = "running"
StatePaused State = "paused"
)
// 定义事件类型
type Event string
// 定义事件常量
const (
EventStart Event = "start"
EventPause Event = "pause"
EventResume Event = "resume"
EventStop Event = "stop"
)
// 有限状态机结构
type FSM struct {
current State
// 状态转换规则:map[当前状态]map[事件]目标状态
transitions map[State]map[Event]State
}
// 创建新的FSM
func NewFSM(initial State) *FSM {
fsm := &FSM{
current: initial,
transitions: make(map[State]map[Event]State),
}
// 设置状态转换规则
fsm.transitions[StateIdle] = map[Event]State{
EventStart: StateRunning,
}
fsm.transitions[StateRunning] = map[Event]State{
EventPause: StatePaused,
EventStop: StateIdle,
}
fsm.transitions[StatePaused] = map[Event]State{
EventResume: StateRunning,
EventStop: StateIdle,
}
return fsm
}
// 处理事件
func (f *FSM) HandleEvent(event Event) error {
if transitions, ok := f.transitions[f.current]; ok {
if nextState, ok := transitions[event]; ok {
fmt.Printf("Transitioning from %s to %s\n", f.current, nextState)
f.current = nextState
return nil
}
}
return fmt.Errorf("invalid transition from %s with event %s", f.current, event)
}
func main() {
fsm := NewFSM(StateIdle)
// 测试状态转换
events := []Event{EventStart, EventPause, EventResume, EventStop}
for _, event := range events {
if err := fsm.HandleEvent(event); err != nil {
fmt.Println("Error:", err)
}
}
}
使用fsm库
Golang有一个流行的FSM库github.com/looplab/fsm
,下面是使用示例:
package main
import (
"fmt"
"github.com/looplab/fsm"
)
func main() {
// 定义FSM
fsm := fsm.NewFSM(
"idle", // 初始状态
fsm.Events{
// 格式: 事件名称, 源状态列表, 目标状态
{Name: "start", Src: []string{"idle"}, Dst: "running"},
{Name: "pause", Src: []string{"running"}, Dst: "paused"},
{Name: "resume", Src: []string{"paused"}, Dst: "running"},
{Name: "stop", Src: []string{"running", "paused"}, Dst: "idle"},
},
fsm.Callbacks{
// 状态转换前后的回调函数
"enter_state": func(e *fsm.Event) {
fmt.Printf("Entering state: %s\n", e.Dst)
},
"leave_state": func(e *fsm.Event) {
fmt.Printf("Leaving state: %s\n", e.Src)
},
"after_start": func(e *fsm.Event) {
fmt.Println("After start event")
},
},
)
// 打印当前状态
fmt.Println("Current state:", fsm.Current())
// 触发事件
err := fsm.Event("start")
if err != nil {
fmt.Println(err)
}
fmt.Println("Current state:", fsm.Current())
err = fsm.Event("pause")
if err != nil {
fmt.Println(err)
}
fmt.Println("Current state:", fsm.Current())
err = fsm.Event("resume")
if err != nil {
fmt.Println(err)
}
fmt.Println("Current state:", fsm.Current())
err = fsm.Event("stop")
if err != nil {
fmt.Println(err)
}
fmt.Println("Current state:", fsm.Current())
}
fsm库高级特性
- 条件转换:可以在回调中添加条件逻辑
fsm := fsm.NewFSM(
"closed",
fsm.Events{
{Name: "open", Src: []string{"closed"}, Dst: "open"},
{Name: "close", Src: []string{"open"}, Dst: "closed"},
},
fsm.Callbacks{
"before_open": func(e *fsm.Event) {
if someCondition {
e.Cancel()
}
},
},
)
- 异步事件处理:
fsm.AsyncEvent("open", func(e *fsm.Event) {
if e.Err != nil {
fmt.Println("Error:", e.Err)
} else {
fmt.Println("Door opened successfully")
}
})
- 获取所有可能的事件:
availableEvents := fsm.AvailableTransitions()
fmt.Println("Available events:", availableEvents)
实际应用示例:订单状态机
package main
import (
"fmt"
"github.com/looplab/fsm"
)
type Order struct {
ID string
State string
FSM *fsm.FSM
}
func NewOrder(id string) *Order {
order := &Order{
ID: id,
State: "created",
}
order.FSM = fsm.NewFSM(
"created",
fsm.Events{
{Name: "pay", Src: []string{"created"}, Dst: "paid"},
{Name: "ship", Src: []string{"paid"}, Dst: "shipped"},
{Name: "deliver", Src: []string{"shipped"}, Dst: "delivered"},
{Name: "cancel", Src: []string{"created", "paid"}, Dst: "cancelled"},
},
fsm.Callbacks{
"enter_state": func(e *fsm.Event) {
order.State = e.Dst
fmt.Printf("Order %s changed state to %s\n", order.ID, order.State)
},
},
)
return order
}
func main() {
order := NewOrder("12345")
// 处理订单流程
events := []string{"pay", "ship", "deliver"}
for _, event := range events {
err := order.FSM.Event(event)
if err != nil {
fmt.Printf("Failed to process %s: %v\n", event, err)
break
}
}
// 尝试非法转换
err := order.FSM.Event("pay")
if err != nil {
fmt.Println("Expected error:", err)
}
}
总结
Golang中实现有限状态机有多种方式:
- 自定义实现 - 适合简单场景
- 使用fsm库 - 提供更丰富的功能,如回调、异步事件等
fsm库的主要优点:
- 清晰的状态转换定义
- 丰富的回调机制
- 线程安全
- 支持条件转换
- 提供当前可用事件查询
在实际项目中,FSM特别适合管理有明确状态转换的业务对象,如订单、工作流、游戏角色状态等。