当前位置: 首页 > 工具软件 > golang-101 > 使用案例 >

golang-设计模式-开闭原则-学习笔记

金宣
2023-12-01

【1】基本理论    
    开闭原则的英文全称是 Open Closed Principle,简写为 OCP。即添加一个新的功能应该是,在已有代码基础上扩展代码(新增模块、类、方法等),而非修改已有代码(修改模块、类、方法等)。
    
【2】功能描述
    假设现在有一个API接口监控告警的需求:可以根据接口配置不同的监控维度(Tps,错误数),然后发送告警通知。后续如果要新增新的维度(eg:超时监控),可以平行扩展代码,以较小代价完成代码修改。

【3】设计思路
    监控告警的主要功能是查询对应API接口的告警规则,按照各个维度依次判断是否超过告警阈值,然后发送告警。我们可以抽象一个告警处理器接口AlertHandler,包含Check(info *ApiInfo)方法去判断当前apiinfo是否需要触发告警,让不同的告警规则去实现这个接口(eg:TPS告警处理-TpsAlertHandler,错误告警处理-ErrAlertHandler),然后将所有实现的告警规则实例放在告警处理器链表中(类似于责任链模式),遍历每个实例进行告警处理。


    当我们需要添加新的告警维度的时候,比如超时数达到阈值告警,只需要做三处改动:
    (1)当前ApiInfo中添加超时统计字段和对应调用方传参;
    (2)添加新的TimeoutAlertHander类;
    (3)将TimeoutAlertHander类添加到告警处理器责任链中;


    这样按照定义的接口扩展点,平行扩展功能,不仅对原有代码结构影响较小,而且不会影响原有的告警功能。

【4】Demo实战    
(说明:带//add的注释 对应代码行为新增超时告警功能对代码的修改)

package main

import "fmt"

//Api数据指标 ApiInfo <public数据结构>
// Api数据指标
type ApiInfo struct {
	Api        string
	RequestCnt int64
	ErrCnt     int64
	DurOfSecs  int64
	TimeoutCnt int64 //add
}

//告警处理器群 Alertx
// 告警处理器接口
type AlertHandler interface {
	Check(info *ApiInfo)
}

// 告警处理器责任链
type Alertx struct {
	alertHandlersList []AlertHandler // 注册存储不同告警功能模块
}

func NewAlertx() *Alertx {
	return &Alertx{
		alertHandlersList: make([]AlertHandler, 0),
	}
}

//添加告警处理器
func (a *Alertx) AddHandler(aHandler AlertHandler) {
	a.alertHandlersList = append(a.alertHandlersList, aHandler)
}

//遍历责任链
func (a *Alertx) CheckAll(aInfo *ApiInfo) {
	for _, handler := range a.alertHandlersList {
		handler.Check(aInfo)
	}
}

// 报警规则
const (
	DEFAULT_RULE_MAXTIPS      = 99999
	DEFAULT_RULE_ERRCOUNT     = 99999
	DEFAULT_RULE_TIMEOUTCOUNT = 99999
)

type RuleData struct {
	maxTps          int64
	maxErrorCount   int64
	maxTimeOutCount int64 //add
}

type AlertRule struct {
	mpAlertConfig map[string]*RuleData
}

func NewAlertRule() *AlertRule {
	mp := make(map[string]*RuleData)
	//add:maxTimeOutCount的配置
	mp["getOrderInfo"] = &RuleData{maxTps: 100, maxErrorCount: 101, maxTimeOutCount: 5}
	mp["getEvaluates"] = &RuleData{maxTps: 200, maxErrorCount: 3, maxTimeOutCount: 5}
	return &AlertRule{mpAlertConfig: mp}
}

// tps阈值
func (a *AlertRule) GetTpsCount(api string) int64 {
	config, ok := a.mpAlertConfig[api]
	if ok {
		return config.maxTps
	}
	return DEFAULT_RULE_MAXTIPS
}

// 错误数阈值
func (a *AlertRule) GetErrCount(api string) int64 {
	config, ok := a.mpAlertConfig[api]
	if ok {
		return config.maxErrorCount
	}
	return DEFAULT_RULE_ERRCOUNT
}

//add: 获取超时数阈值
func (a *AlertRule) GetTimeoutCount(api string) int64 {
	config, ok := a.mpAlertConfig[api]
	if ok {
		return config.maxTimeOutCount
	}
	return DEFAULT_RULE_TIMEOUTCOUNT
}

// 告警通知

type EmergencyLevelType int

const (
	EL_URGENCY EmergencyLevelType = 0
	EL_SEVERE                     = 4
	EL_NORMAL                     = 5
)

type Notification struct{}

func (n *Notification) Notify(level EmergencyLevelType, msg string) {
	fmt.Printf("[Notify]Level:%v, msg:%s\n", level, msg)
}

//实现AlertHandler接口,按照TPS规则
type TpsAlertHandler struct {
	rule         *AlertRule
	notification *Notification
}

func NewTpsAlertHandler(rule *AlertRule, notification *Notification) *TpsAlertHandler {
	return &TpsAlertHandler{
		rule:         rule,
		notification: notification,
	}

}
func (t *TpsAlertHandler) Check(info *ApiInfo) {
	tps := info.RequestCnt / info.DurOfSecs
	if tps > t.rule.GetTpsCount(info.Api) {
		t.notification.Notify(EL_URGENCY, "TPS Too high!")
	}
	fmt.Println("TPS Alert Done")
}

//实现AlertHandler接口,按照Alert规则
type ErrAlertHandler struct {
	rule         *AlertRule
	notification *Notification
}

func NewErrAlertHandler(rule *AlertRule, notification *Notification) *ErrAlertHandler {
	return &ErrAlertHandler{
		rule:         rule,
		notification: notification,
	}
}

// 实现AlertHandler接口
func (e *ErrAlertHandler) Check(info *ApiInfo) {
	if info.ErrCnt > e.rule.GetErrCount(info.Api) {
		e.notification.Notify(EL_URGENCY, "ERR Count Too High!")
	}
	fmt.Println("Err Alert Done")
}

//add :新增超时监控维度,实现AlertHandler接口,按照Timeout规则
type TimeoutAlertHandler struct {
	rule         *AlertRule
	notification *Notification
}

func NewTimeoutAlertHandler(rule *AlertRule, notification *Notification) *TimeoutAlertHandler {
	return &TimeoutAlertHandler{
		rule:         rule,
		notification: notification,
	}
}

func (t *TimeoutAlertHandler) Check(info *ApiInfo) {
	if info.TimeoutCnt > t.rule.GetTimeoutCount(info.Api) {
		t.notification.Notify(EL_SEVERE, "Timeout Count Too High!")
	}
	fmt.Println("Timeout Alert Done")
}

func main() {
	alerts := NewAlertx()
	infos := &ApiInfo{
		Api:        "getOrderInfo",
		RequestCnt: 100,
		ErrCnt:     100,
		DurOfSecs:  1,
		TimeoutCnt: 100, //add :设置当前api的超时统计数
	}
	alerts.AddHandler(NewTpsAlertHandler(NewAlertRule(), &Notification{}))
	alerts.AddHandler(NewErrAlertHandler(NewAlertRule(), &Notification{}))
	alerts.AddHandler(NewTimeoutAlertHandler(NewAlertRule(), &Notification{})) //add:添加超时告警搞告警责任链
	alerts.CheckAll(infos)
}

运行结果:

TPS Alert Done
Err Alert Done
[Notify]Level:4, msg:Timeout Count Too High!
Timeout Alert Done

 类似资料: