├── .gitignore ├── LICENSE ├── README.md ├── go.mod ├── internal └── order │ ├── event.go │ ├── fsm.go │ ├── handler.go │ ├── handler_option.go │ └── state.go ├── main.go └── order_flow.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | *.idea 8 | 9 | # Test binary, built with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # Dependency directories (remove the comment below to include it) 16 | # vendor/ 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 新亮笔记 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 订单流程图 2 | 3 | ![订单流转图](https://i.loli.net/2021/07/02/N58rKtCGUDbdWJv.png) 4 | 5 | 基于上述订单流转流程,使用有限状态机的方式用 `Golang` 代码进行实现。 6 | 7 | ## 运行结果 8 | 9 | ``` 10 | 正在处理创建订单逻辑,订单ID(1), 订单名称(测试订单) ... 处理完毕! 11 | 发送短信,给(18888888888)发送了(恭喜你预定成功了!) 12 | 操作[创建订单],状态从 [默认] 变成 [已预订] 13 | [警告] 状态(已预订)不允许操作(修改订单) 14 | 操作[确定订单],状态从 [已预订] 变成 [已确认] 15 | 操作[修改订单],状态从 [已确认] 变成 [已预订] 16 | 操作[确定订单],状态从 [已预订] 变成 [已确认] 17 | 操作[支付订单],状态从 [已确认] 变成 [已锁定] 18 | ``` 19 | 20 | ## 有限状态机 21 | 22 | ### 简介 23 | 有限状态机(Finite-state machine,简写:FSM)又可以称作有限状态自动机,简称状态机。 24 | 25 | 它必须是可以附着在某种事物上的,且该事物的状态是有限的,通过某些触发事件,会让其状态发生转换。为此,有限状态机就是描述这些有限的状态和触发事件及转换行为的数学模型。 26 | 27 | PS:关于状态机的简介可以去网上搜索,以上供参考。 28 | 29 | ### 特性 30 | - 状态总数(state)是有限的。 31 | - 任一时刻,只处在一种状态之中。 32 | - 某种条件下,会从一种状态转变(transition)到另一种状态。 33 | 34 | ## 联系作者 35 | 36 | ![联系作者](https://i.loli.net/2021/07/02/cwiLQ13CRgJIS86.jpg) 37 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/xinliangnote/go-fsm-order 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /internal/order/event.go: -------------------------------------------------------------------------------- 1 | package order 2 | 3 | // 定义订单事件 4 | const ( 5 | EventCreate = Event("创建订单") 6 | EventConfirm = Event("确定订单") 7 | EventModify = Event("修改订单") 8 | EventPay = Event("支付订单") 9 | ) 10 | 11 | // 定义订单事件对应的处理方法 12 | var eventHandler = map[Event]Handler{ 13 | EventCreate: handlerCreate, 14 | EventConfirm: handlerConfirm, 15 | EventModify: handlerModify, 16 | EventPay: handlerPay, 17 | } 18 | -------------------------------------------------------------------------------- /internal/order/fsm.go: -------------------------------------------------------------------------------- 1 | package order 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "sync" 7 | ) 8 | 9 | type State int // 状态 10 | type Event string // 事件 11 | type Handler func(opt *Opt) (State, error) // 处理方法,并返回新的状态 12 | 13 | // FSM 有限状态机 14 | type FSM struct { 15 | mu sync.Mutex // 排他锁 16 | state State // 当前状态 17 | handlers map[State]map[Event]Handler // 当前状态可触发的有限个事件 18 | } 19 | 20 | // 获取当前状态 21 | func (f *FSM) getState() State { 22 | return f.state 23 | } 24 | 25 | // 设置当前状态 26 | func (f *FSM) setState(newState State) { 27 | f.state = newState 28 | } 29 | 30 | // addHandlers 添加事件和处理方法 31 | func (f *FSM) addHandlers() (*FSM, error) { 32 | if statusEvent == nil || len(statusEvent) <= 0 { 33 | return nil, errors.New("[警告] 未定义 statusEvent") 34 | } 35 | 36 | for state, events := range statusEvent { 37 | if len(events) <= 0 { 38 | return nil, errors.New(fmt.Sprintf("[警告] 状态(%s)未定义事件", StatusText(state))) 39 | } 40 | 41 | for _, event := range events { 42 | handler := eventHandler[event] 43 | if handler == nil { 44 | return nil, errors.New(fmt.Sprintf("[警告] 事件(%s)未定义处理方法", event)) 45 | } 46 | 47 | if _, ok := f.handlers[state]; !ok { 48 | f.handlers[state] = make(map[Event]Handler) 49 | } 50 | 51 | if _, ok := f.handlers[state][event]; ok { 52 | return nil, errors.New(fmt.Sprintf("[警告] 状态(%s)事件(%s)已定义过", StatusText(state), event)) 53 | } 54 | 55 | f.handlers[state][event] = handler 56 | } 57 | } 58 | 59 | return f, nil 60 | } 61 | 62 | // Call 事件处理 63 | func (f *FSM) Call(event Event, opts ...Option) (State, error) { 64 | f.mu.Lock() 65 | defer f.mu.Unlock() 66 | 67 | events := f.handlers[f.getState()] 68 | if events == nil { 69 | return 0, errors.New(fmt.Sprintf("[警告] 状态(%s)未定义任何事件", StatusText(f.getState()))) 70 | } 71 | 72 | opt := new(Opt) 73 | for _, f := range opts { 74 | f(opt) 75 | } 76 | 77 | fn, ok := events[event] 78 | if !ok { 79 | return 0, errors.New(fmt.Sprintf("[警告] 状态(%s)不允许操作(%s)", StatusText(f.getState()), event)) 80 | } 81 | 82 | status, err := fn(opt) 83 | if err != nil { 84 | return 0, err 85 | } 86 | 87 | oldState := f.getState() 88 | f.setState(status) 89 | newState := f.getState() 90 | 91 | fmt.Println(fmt.Sprintf("操作[%s],状态从 [%s] 变成 [%s]", event, StatusText(oldState), StatusText(newState))) 92 | 93 | return f.getState(), nil 94 | } 95 | 96 | // NewFSM 实例化 FSM 97 | func NewFSM(initState State) (fsm *FSM, err error) { 98 | fsm = new(FSM) 99 | fsm.state = initState 100 | fsm.handlers = make(map[State]map[Event]Handler) 101 | 102 | fsm, err = fsm.addHandlers() 103 | if err != nil { 104 | return 105 | } 106 | 107 | return 108 | } 109 | -------------------------------------------------------------------------------- /internal/order/handler.go: -------------------------------------------------------------------------------- 1 | package order 2 | 3 | import "fmt" 4 | 5 | var ( 6 | // handlerCreate 创建订单 7 | handlerCreate = Handler(func(opt *Opt) (State, error) { 8 | message := fmt.Sprintf("正在处理创建订单逻辑,订单ID(%d), 订单名称(%s) ... 处理完毕!", opt.OrderId, opt.OrderName) 9 | fmt.Println(message) 10 | 11 | if opt.HandlerSendSMS != nil { 12 | _ = opt.HandlerSendSMS("18888888888", "恭喜你预定成功了!") 13 | } 14 | 15 | return StatusReserved, nil 16 | }) 17 | 18 | // handlerConfirm 确认订单 19 | handlerConfirm = Handler(func(opt *Opt) (State, error) { 20 | return StatusConfirmed, nil 21 | }) 22 | 23 | // handlerModify 修改订单 24 | handlerModify = Handler(func(opt *Opt) (State, error) { 25 | return StatusReserved, nil 26 | }) 27 | 28 | // handlerPay 支付订单 29 | handlerPay = Handler(func(opt *Opt) (State, error) { 30 | return StatusLocked, nil 31 | }) 32 | ) 33 | -------------------------------------------------------------------------------- /internal/order/handler_option.go: -------------------------------------------------------------------------------- 1 | package order 2 | 3 | type Option func(*Opt) 4 | 5 | // SendSMS 发送短信 6 | type SendSMS func(mobile, content string) error 7 | 8 | // Opt 定义 Handler 所需参数 9 | type Opt struct { 10 | OrderId int 11 | OrderName string 12 | 13 | HandlerSendSMS SendSMS 14 | } 15 | 16 | // WithOrderId 设置订单ID 17 | func WithOrderId(id int) Option { 18 | return func(opt *Opt) { 19 | opt.OrderId = id 20 | } 21 | } 22 | 23 | // WithOrderName 设置订单名称 24 | func WithOrderName(name string) Option { 25 | return func(opt *Opt) { 26 | opt.OrderName = name 27 | } 28 | } 29 | 30 | // WithHandlerSendSMS 设置发送短信 31 | func WithHandlerSendSMS(sendSms SendSMS) Option { 32 | return func(opt *Opt) { 33 | opt.HandlerSendSMS = sendSms 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /internal/order/state.go: -------------------------------------------------------------------------------- 1 | package order 2 | 3 | // 定义订单状态 4 | const ( 5 | StatusDefault = State(0) 6 | StatusReserved = State(10) 7 | StatusConfirmed = State(20) 8 | StatusLocked = State(30) 9 | ) 10 | 11 | // statusText 定义订单状态文案 12 | var statusText = map[State]string{ 13 | StatusDefault: "默认", 14 | StatusReserved: "已预订", 15 | StatusConfirmed: "已确认", 16 | StatusLocked: "已锁定", 17 | } 18 | 19 | // statusEvent 定义订单状态对应的可操作事件 20 | var statusEvent = map[State][]Event{ 21 | StatusDefault: {EventCreate}, 22 | StatusReserved: {EventConfirm}, 23 | StatusConfirmed: {EventModify, EventPay}, 24 | } 25 | 26 | func StatusText(status State) string { 27 | return statusText[status] 28 | } 29 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/xinliangnote/go-fsm-order/internal/order" 6 | ) 7 | 8 | func main() { 9 | // 通过订单ID 或 其他信息查询到订单状态 10 | orderStatus := order.StatusDefault 11 | 12 | orderMachine, err := order.NewFSM(orderStatus) 13 | if err != nil { 14 | fmt.Println(err.Error()) 15 | return 16 | } 17 | 18 | // 创建订单,订单创建成功后再给用户发送短信 19 | if _, err = orderMachine.Call(order.EventCreate, 20 | order.WithOrderId(1), 21 | order.WithOrderName("测试订单"), 22 | order.WithHandlerSendSMS(sendSMS), 23 | ); err != nil { 24 | fmt.Println(err.Error()) 25 | } 26 | 27 | // 修改订单 28 | if _, err = orderMachine.Call(order.EventModify); err != nil { 29 | fmt.Println(err.Error()) 30 | } 31 | 32 | // 确认订单 33 | if _, err = orderMachine.Call(order.EventConfirm); err != nil { 34 | fmt.Println(err.Error()) 35 | } 36 | 37 | // 修改订单 38 | if _, err = orderMachine.Call(order.EventModify); err != nil { 39 | fmt.Println(err.Error()) 40 | } 41 | 42 | // 确认订单 43 | if _, err = orderMachine.Call(order.EventConfirm); err != nil { 44 | fmt.Println(err.Error()) 45 | } 46 | 47 | // 支付订单 48 | if _, err = orderMachine.Call(order.EventPay); err != nil { 49 | fmt.Println(err.Error()) 50 | } 51 | } 52 | 53 | // sendSMS 发送短信,为了演示写在了这里 54 | func sendSMS(mobile, content string) error { 55 | fmt.Println(fmt.Sprintf("发送短信,给(%s)发送了(%s)", mobile, content)) 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /order_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xinliangnote/go-fsm-order/e689baf913bab1656891055ff9c771853485d4c3/order_flow.png --------------------------------------------------------------------------------