Go设计模式之开闭设计原则
面向对象设计原则
在面向对象设计中,需要按照以下六个原则进行设计,代码才具有可读性/可扩展性等,实现高内聚低耦合。
开闭原则
一个软件实体如类,模块和函数应该对扩展开放,对修改关闭。
- 用抽象构建框架,用实现扩展细节
- 不以改动原有类的方式来实现新需求,而是应该以实现事先抽象出来的接口(或具体类继承抽象类)的方式来实现。
发现问题
如下场景,设计一个告警模块,根据不同阈值条件,发送不同的应急通知措施。
// 模块功能:当接口请求个数超过某个阈值发出告警
// 存储告警规则,可自由设置
type AlertRule struct {}
func (a *AlertRule) getMathedRule(api string) int64{
return 0
}
// 告警通知类,支持短信/微信等各种渠道
type Notification struct {}
func (n *Notification) notify(level string) {
}
// 监控接口
type Alert struct {
rule *AlertRule
notification *Notification
}
// 构造函数创建实例,如果单实例参考之前文档单实例创建方式
func NewAlert(rule *AlertRule, notification *Notification) *Alert {
return &Alert{
rule:rule,
notification:notification,
}
}
func (a *Alert) check(api string, requestCnt, errCnt, durationOfSeconds int64) {
tps := requestCnt/durationOfSeconds
if tps > a.rule.getMathedRule(api) {
a.notification.notify("URGENCY")
}
if errCnt > a.rule.getMathedRule(api) {
a.notification.notify("SEVERE")
}
}
以上代码实现非常简单,但是当需要增加一个新功能,比如当每秒钟超时请求个数超过某个阈值,需要触发告警通知,针对以上代码设计需要修改两处:1,修改check接口增加timeout入参,2,check内部增加超时逻辑代码,
// 接口处增加timeout入参
func (a *Alert) check(api string, requestCnt, errCnt, timeout, durationOfSeconds int64) {
tps := requestCnt/durationOfSeconds
if tps > a.rule.getMathedRule(api) {
a.notification.notify("URGENCY")
}
if errCnt > a.rule.getMathedRule(api) {
a.notification.notify("SEVERE")
}
// 此处增加超时逻辑
}
开闭原则实现
type Alertx struct {
alertHandlers []AlertHandler // 注册存储不同告警功能模块
}
type ApiStatInfo struct {
api string
rstcnt int64
errcnt int64
durOfSecs int64
}
// 设计接口
type AlertHandler interface {
check(info ApiStatInfo)
}
// 构造函数
func NewAlertx() *Alertx{
return &Alertx{
alertHandlers:make([]AlertHandler,0),
}
}
func (a *Alertx) addAlerHandler(handler AlertHandler) {
a.alertHandlers = append(a.alertHandlers,handler)
}
func (a *Alertx) check(info ApiStatInfo) {
for _,handle := range a.alertHandlers {
handle.check(info)
}
}
// 实现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 ApiStatInfo) {
tps := info.rstcnt/info.durOfSecs
if tps > t.rule.getMathedRule(info.api) {
t.notification.notify("URGENCY")
}
fmt.Println("TPS")
}
// 实现AlertHandler接口,按照Err规则实现
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 ApiStatInfo) {
if info.errcnt > e.rule.getMathedRule(info.api) {
e.notification.notify("SEVER")
}
fmt.Println("Err")
}
那么新增timeOut规则,只需要实现AlertHandler接口,并注册到Alertx。
// 那么新增timeOut规则,只需要实现AlertHandler接口,并注册到Alertx
type TimeOutAlertHandler struct {
rule *AlertRule
notification *Notification
}
func NewTimeAlertHandler(rule *AlertRule, notification *Notification) *TimeOutAlertHandler{
return &TimeOutAlertHandler{
rule:rule,
notification:notification,
}
}
func (t *TimeOutAlertHandler) check(info ApiStatInfo) {
fmt.Println("TimeOut!")
}
测试用例
func TestAlertx(t *testing.T) {
alter := NewAlertx()
rule := new(AlertRule)
apiInfo := ApiStatInfo{
rstcnt:1000,
errcnt:10,
durOfSecs:50,
}
notification := new(Notification)
alter.addAlerHandler(NewTpsAlertHandler(rule,notification))
alter.addAlerHandler(NewErrAlertHandler(rule,notification))
alter.addAlerHandler(NewTimeAlertHandler(rule,notification))
alter.check(apiInfo)
}
完整代码实现可以访问个人Github主页查看实例。
编辑于 2020-10-03 22:27