go: 状态模式
2023-04-18 16:17:25 时间
状态模式避免了一个程序中出现大量的switch case/if
。实际上是将状态的转换拆分到不同的子类中实现。
在实现子类的时候,只需要考虑当前状态,传入的条件,下一个状态。比较节省脑容量。
这是一个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)
}
测试用例
// 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()
}
}
相关文章
- 【技术种草】cdn+轻量服务器+hugo=让博客“云原生”一下
- CLB运维&运营最佳实践 ---访问日志大洞察
- vnc方式登陆服务器
- 轻松学排序算法:眼睛直观感受几种常用排序算法
- 十二个经典的大数据项目
- 为什么使用 CDN 内容分发网络?
- 大数据——大数据默认端口号列表
- Weld 1.1.5.Final,JSR-299 的框架
- JavaFX 2012:彻底开源
- 提升as3程序性能的十大要点
- 通过凸面几何学进行独立于边际的在线多类学习
- 利用行动影响的规律性和部分已知的模型进行离线强化学习
- ModelLight:基于模型的交通信号控制的元强化学习
- 浅谈Visual Source Safe项目分支
- 基于先验知识的递归卡尔曼滤波的代理人联合状态和输入估计
- 结合网络结构和非线性恢复来提高声誉评估的性能
- 最佳实践丨云开发CloudBase多环境管理实践
- TimeVAE:用于生成多变量时间序列的变异自动编码器
- 具有线性阈值激活的神经网络:结构和算法
- 内网渗透之横向移动 -- 从域外向域内进行密码喷洒攻击