go: 状态模式 状态模式避免了一个程序中出现大量的`switch case/if`。实际上是将状态的转换拆分到不同的子类中实现。 在实现子类的时候,只需要考虑当前状态,传入的条件,下一个状态。比较节省脑容量。 这是一个go实现的状态模式的例子。 ```go /* statemode 这是一个状态模式的示例 状态根据当前的信息转换 normal -心跳过期-> preOffline -继续过期-> offline -心跳恢复-> normal */ package statemode import ( "fmt" "math" "time" "github.com/sirupsen/logrus" ) type State interface { // Change 状态根据传入的info进行改变,返回新的状态或者错误 Change(info map[string]string) (State, error) } type NormalState struct { } func (n *NormalState) Change(info map[string]string) (State, error) { ttime, err := datautils.ToInt(info["time"]) if err != nil { return nil, err } // 判定心跳时间如果超过当前时间3秒,则状态转换为preOffline if abs(time.Now().Unix()-int64(ttime)) > 3 { return &PreOfflineState{}, nil } return n, nil } type PreOfflineState struct { } func (p *PreOfflineState) Change(info map[string]string) (State, error) { ttime, err := datautils.ToInt(info["time"]) if err != nil { return nil, err } // 当在preOffline的时候,心跳继续过期3秒,转换为offline状态 if abs(time.Now().Unix()-int64(ttime)) > 3 { return &OfflineState{}, nil } else { // 当在preOffline的时候,心跳恢复,转换为normal状态 return &NormalState{}, nil } } type OfflineState struct { } func (o *OfflineState) Change(info map[string]string) (State, error) { // offline状态为最终状态,不能再转换 return nil, fmt.Errorf("offline state cannot change") } func abs(a interface{}) float64 { v, err := datautils.ToFloat64(a) if err != nil { logrus.Fatal(err) } return math.Abs(v) } ``` 测试用例 ```go // statemode 这是一个状态模式的示例 package statemode import ( "reflect" "testing" "time" "github.com/sirupsen/logrus" ) func TestNormalState_Change(t *testing.T) { initState := &NormalState{} normalState, err := initState.Change(map[string]string{ "time": datautils.ToStr(time.Now().Unix()), }) if err != nil { t.Fatal(err) } _, ok := normalState.(*NormalState) if !ok { t.Fatal() } preOfflineState, err := normalState.Change(map[string]string{ "time": datautils.ToStr(time.Now().Unix() - 10), }) if err != nil { t.Fatal(err) } _, ok = preOfflineState.(*PreOfflineState) logrus.Infof("nextState preoffline:%v", reflect.TypeOf(preOfflineState)) if !ok { t.Fatal() } offlineState, err := preOfflineState.Change(map[string]string{ "time": datautils.ToStr(time.Now().Unix() - 10), }) if err != nil { t.Fatal(err) } _, ok = offlineState.(*OfflineState) logrus.Infof("nextState offline:%v", reflect.TypeOf(offlineState)) if !ok { t.Fatal() } normalState, err = preOfflineState.Change(map[string]string{ "time": datautils.ToStr(time.Now().Unix()), }) if err != nil { t.Fatal(err) } _, ok = normalState.(*NormalState) logrus.Infof("nextState back to normal:%v", reflect.TypeOf(normalState)) if !ok { t.Fatal() } } ``` 来自 大脸猪 写于 2021-11-23 14:57 -- 更新于2021-11-23 14:59 -- 0 条评论