前言
在设计电商零碎订单模块时,订单会波及各种状态以及状态与状态之间的流转,可扩展性
、可维护性
是咱们须要关注的重点!本文分享一下我的技术计划。
如上图,应用 golang
实现上图的订单流转,同时当后续减少订单状态或订单事件时,能够进行疾速实现。
目标
对于订单状态的解决,应用对立入口,进步程序的 可扩展性
和 可维护性
。
逻辑剖析
订单状态包含:默认
、已预订
、已确认
、已锁定
。
订单事件包含:创立订单
、确认订单
、批改订单
、领取订单
。
通过上图咱们还晓得了状态与事件之间的关系,比方只有 已确认
的订单才能够进行 批改订单
。
须要思考如下问题:
- 当订单状态减少时,如何尽可能少的改变或改变对历史影响不大?
- 如果在同一入口调用,每个事件的解决办法须要的入参都有所不同,如何解决?
- 当某个事件实现后,有可能会进行发短信或客户端 Push 的操作,如何解决?
- 有可能某个事件,在不同平台(C端、商家后盾、治理平台)的解决逻辑也有些不同,如何解决?
如何设计代码可能解决以上问题?
上面是我的一种代码实现,供大家参考,实现了在 创立订单
时,进行传入参数和实现后给用户发送短信,其余事件的操作,同理就能够实现。
代码实现
定义状态
// 定义订单状态const ( StatusDefault = State(0) StatusReserved = State(10) StatusConfirmed = State(20) StatusLocked = State(30))// statusText 定义订单状态文案var statusText = map[State]string{ StatusDefault: "默认", StatusReserved: "已预订", StatusConfirmed: "已确认", StatusLocked: "已锁定",}// statusEvent 定义订单状态对应的可操作事件var statusEvent = map[State][]Event{ StatusDefault: {EventCreate}, StatusReserved: {EventConfirm}, StatusConfirmed: {EventModify, EventPay},}func StatusText(status State) string { return statusText[status]}
当有新订单状态的减少时,在此文件中减少相应状态即可,同时保护好订单状态与订单事件之间的关系。
定义事件
// 定义订单事件const ( EventCreate = Event("创立订单") EventConfirm = Event("确定订单") EventModify = Event("批改订单") EventPay = Event("领取订单"))// 定义订单事件对应的解决办法var eventHandler = map[Event]Handler{ EventCreate: handlerCreate, EventConfirm: handlerConfirm, EventModify: handlerModify, EventPay: handlerPay,}
当有新订单事件的减少时,在此文件中减少相应事件即可,同时保护好订单事件与事件实现办法之间的关系。
定义事件的解决办法
var ( // handlerCreate 创立订单 handlerCreate = Handler(func(opt *Opt) (State, error) { message := fmt.Sprintf("正在解决创立订单逻辑,订单ID(%d), 订单名称(%s) ... 处理完毕!", opt.OrderId, opt.OrderName) fmt.Println(message) if opt.HandlerSendSMS != nil { _ = opt.HandlerSendSMS("18888888888", "祝贺你预约胜利了!") } return StatusReserved, nil }) // handlerConfirm 确认订单 handlerConfirm = Handler(func(opt *Opt) (State, error) { return StatusConfirmed, nil }) // handlerModify 批改订单 handlerModify = Handler(func(opt *Opt) (State, error) { return StatusReserved, nil }) // handlerPay 领取订单 handlerPay = Handler(func(opt *Opt) (State, error) { return StatusLocked, nil }))
在此文件中保护具体的事件处理办法,如果逻辑比较复杂能够思考拆分文件解决。
外围代码
type State int // 状态type Event string // 事件type Handler func(opt *Opt) (State, error) // 解决办法,并返回新的状态// FSM 无限状态机type FSM struct { mu sync.Mutex // 排他锁 state State // 以后状态 handlers map[State]map[Event]Handler // 以后状态可触发的无限个事件}// 获取以后状态func (f *FSM) getState() State { return f.state}// 设置以后状态func (f *FSM) setState(newState State) { f.state = newState}// addHandlers 增加事件和解决办法func (f *FSM) addHandlers() (*FSM, error) { ... return f, nil}// Call 事件处理func (f *FSM) Call(event Event, opts ...Option) (State, error) { f.mu.Lock() defer f.mu.Unlock() ... return f.getState(), nil}// NewFSM 实例化 FSMfunc NewFSM(initState State) (fsm *FSM, err error) { fsm = new(FSM) fsm.state = initState fsm.handlers = make(map[State]map[Event]Handler) fsm, err = fsm.addHandlers() if err != nil { return } return}
对订单状态的操作,只须要应用 Call
办法即可!
对于办法 addHandlers
和 Call
的代码就不贴了,在文章前面我提供了源码地址,供大家下载。
调用形式
例如以后状态为 默认状态
,顺次进行如下操作:
创立订单
,状态变为已预订
;批改订单
,不可操作(已预订状态不可批改);确定订单
,状态变为已确认
;批改订单
,状态变为已预订
;确定订单
,状态变为已确认
;领取订单
,状态变为已锁定
;
// 通过订单ID 或 其余信息查问到订单状态orderStatus := order.StatusDefaultorderMachine, err := order.NewFSM(orderStatus)if err != nil { fmt.Println(err.Error()) return}// 创立订单,订单创立胜利后再给用户发送短信if _, err = orderMachine.Call(order.EventCreate, order.WithOrderId(1), order.WithOrderName("测试订单"), order.WithHandlerSendSMS(sendSMS),); err != nil { fmt.Println(err.Error())}// 批改订单if _, err = orderMachine.Call(order.EventModify); err != nil { fmt.Println(err.Error())}// 确认订单if _, err = orderMachine.Call(order.EventConfirm); err != nil { fmt.Println(err.Error())}// 批改订单if _, err = orderMachine.Call(order.EventModify); err != nil { fmt.Println(err.Error())}// 确认订单if _, err = orderMachine.Call(order.EventConfirm); err != nil { fmt.Println(err.Error())}// 领取订单if _, err = orderMachine.Call(order.EventPay); err != nil { fmt.Println(err.Error())}
输入:
正在解决创立订单逻辑,订单ID(1), 订单名称(测试订单) ... 处理完毕!发送短信,给(18888888888)发送了(祝贺你预约胜利了!)操作[创立订单],状态从 [默认] 变成 [已预订][正告] 状态(已预订)不容许操作(批改订单)操作[确定订单],状态从 [已预订] 变成 [已确认]操作[批改订单],状态从 [已确认] 变成 [已预订]操作[确定订单],状态从 [已预订] 变成 [已确认]操作[领取订单],状态从 [已确认] 变成 [已锁定]
小结
以上就是我的技术计划,心愿能对你有所帮忙,感兴趣的能够再进行封装,上述代码已提交到 github go-fsm-order,供下载应用。