有限状态机

好处:逻辑收敛

1.状态转换更加清晰

2.新增转化逻辑,其他地方的代码不用修改

比如对于这样一个状态机:

|----|------------------------|
| 状态 | [草稿,审阅中,已拒绝,已通过,已归档] |
| 事件 | [提交,撤回,拒绝......] |

Go 复制代码
If else写法:
func docIfElse(events []string) {
    state := "草稿"
    
    for _, e := range events {
        fmt.Printf("  [%s] + <%s> → ", state, e)

        if state == "草稿" && e == "提交" {
            state = "审阅中"
        } else if state == "审阅中" && e == "通过" {
            state = "已通过"
        } else if state == "审阅中" && e == "拒绝" {
            state = "已拒绝"
        } else if state == "审阅中" && e == "撤回" {
            state = "草稿"
        } else if state == "已拒绝" && e == "提交" {
            state = "审阅中"
        }
        // ★ 新增状态?要在这里继续堆 else if...

        fmt.Printf("%s\n", state)
    }
}

状态机写法:

Go 复制代码
状态机写法:
// ----- 基础类型 -----
type Transition struct {
    Event string // 触发事件
    Next  string // 目标状态
}

type State struct {
    Name        string
    IsEnd       bool          // 终态标记
    Transitions []*Transition // 该状态的所有合法出口
}

type StateFlow []State

// ----- 引擎(永远不用改)-----

type FSM struct {
    current string
    flow    map[string]*State
}

func NewFSM(flow StateFlow, initial string) *FSM {
    m := make(map[string]*State, len(flow))
    for i := range flow {
        s := &flow[i]
        m[s.Name] = s
    }
    return &FSM{current: initial, flow: m}
}

func (f *FSM) Handle(event string) {
    st, ok := f.flow[f.current]
    if !ok {
        fmt.Printf("  ❓ 未知状态: %s\n", f.current)
        return
    }
    if st.IsEnd {
        fmt.Printf("  [%s] 是终态,不接受任何事件\n", f.current)
        return
    }
    for _, t := range st.Transitions {
        if t.Event == event {
            fmt.Printf("  [%s] + <%s> → %s\n", f.current, event, t.Next)
            f.current = t.Next
            return
        }
    }
    fmt.Printf("  [%s] + <%s> → 无效事件,保持原状态\n", f.current, event)
}

// ============================================================
//  定义文档审批流
// ============================================================

// 第一步:定义可复用的转换(定义一次,到处引用)
var (
    submitTransition   = &Transition{Event: "提交", Next: "审阅中"}
    approveTransition  = &Transition{Event: "通过", Next: "已通过"}
    rejectTransition   = &Transition{Event: "拒绝", Next: "已拒绝"}
    withdrawTransition = &Transition{Event: "撤回", Next: "草稿"}
    archiveTransition  = &Transition{Event: "归档", Next: "已归档"}
)

// 第二步:以"状态"为中心,声明每个状态的合法出口
var docFlow = StateFlow{
    {
        Name: "草稿",
        Transitions: []*Transition{
            submitTransition,   // → 审阅中
        },
    },
    {
        Name: "审阅中", // 表示审阅这个状态,可能会流转到已通过,已拒绝,草稿三个状态
        Transitions: []*Transition{
            approveTransition,  // → 已通过
            rejectTransition,   // → 已拒绝
            withdrawTransition, // → 草稿
        },
    },
    {
        Name: "已拒绝",
        Transitions: []*Transition{
            submitTransition,   // → 审阅中(复用同一个对象!)
        },
    },
    {
        Name: "已通过",
        Transitions: []*Transition{
            archiveTransition,  // → 已归档
        },
    },
    {
        Name:  "已归档",
        IsEnd: true,            // 终态
    },
}

func main() {
    fsm := NewFSM(docFlow, "草稿")
    events := []string{"提交", "拒绝", "提交", "通过", "归档", "提交"}
    for i, e := range events {
        fmt.Printf("[步骤 %d] ", i+1)
        fsm.Handle(e)
    }
}
相关推荐
数智化管理手记2 小时前
精益生产中的TPM管理是什么?一文破解设备零故障的密码
服务器·网络·数据库·低代码·制造·源代码管理·精益工程
@insist1234 小时前
网络工程师-生成树协议(STP/RSTP/MSTP)核心原理与应用
服务器·开发语言·网络工程师·软考·软件水平考试
nbwenren6 小时前
Springboot中SLF4J详解
java·spring boot·后端
zzzsde7 小时前
【Linux】库的制作和使用(3)ELF&&动态链接
linux·运维·服务器
CQU_JIAKE7 小时前
4.3【A]
linux·运维·服务器
AI周红伟7 小时前
OpenClaw是什么?OpenClaw能做什么?OpenClaw详细介绍及保姆级部署教程-周红伟
大数据·运维·服务器·人工智能·微信·openclaw
TechWayfarer7 小时前
科普:IP归属地中的IDC/机房/家庭宽带有什么区别?
服务器·网络·tcp/ip
helx827 小时前
SpringBoot中自定义Starter
java·spring boot·后端
Amctwd8 小时前
【Linux】OpenCode 安装教程
linux·运维·服务器
KOYUELEC光与电子努力加油8 小时前
JAE日本航空端子推出支持自走式机器人的自主充电功能浮动式连接器“DW15系列“方案与应用
服务器·人工智能·机器人·无人机