前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >go: 状态模式

go: 状态模式

作者头像
超级大猪
发布2021-12-24 14:27:42
2890
发布2021-12-24 14:27:42
举报
文章被收录于专栏:大猪的笔记大猪的笔记

状态模式避免了一个程序中出现大量的switch case/if。实际上是将状态的转换拆分到不同的子类中实现。 在实现子类的时候,只需要考虑当前状态,传入的条件,下一个状态。比较节省脑容量。 这是一个go实现的状态模式的例子。

代码语言:javascript
复制
/* 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)
}

测试用例

代码语言:javascript
复制
// 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 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档