乐趣区

关于golang:手撸golang-行为型设计模式-责任链模式

手撸 golang 行为型设计模式 责任链模式

缘起

最近温习设计模式
拜读谭勇德的 << 设计模式就该这样学 >>
本系列笔记拟采纳 golang 练习之

责任链模式

责任链模式(Chain of Responsibility Pattern)将链中每一个节点都看作一个对象,每个节点解决的申请均不同,且外部主动保护下一个节点对象。当一个申请从链式的首端收回时,会沿着责任链预设的门路顺次传递到每一个节点对象,直至被链中的某个对象解决为止,属于行为型设计模式。责任链模式次要实用于以下利用场景。(1)多个对象能够解决同一申请,但具体由哪个对象解决则在运行时动静决定。(2)在不明确指定接收者的状况下,向多个对象中的一个提交申请。(3)可动静指定一组对象解决申请。(摘自 谭勇德 << 设计模式就该这样学 >>)

场景

  • 某业务零碎, 须要将日志按重大等级(Debug/Info/Error), 离开不同文件
  • 码农王二狗, 于是设计了 DebugLogger, InfoLogger, ErrorLogger 三个日志类
  • 业务层依据日志输入等级, 别离调用不同的 logger
  • Leader 张阿蛋审阅后十分不称心

    • 张阿蛋: 狗子, 写个日志还得调用三个类, 业务 team 的人还不把咱们骂得狗血淋头
    • 王二狗: … 张哥, 那你的意见是?
    • 张阿蛋: 就一个 ILogger 门面接口, 把 Debug/Info/Error 办法都放进去; 外面用个责任链, Debug/Info/Error 各自做一个节点.
    • 王二狗: 张哥, 强!

设计

  • ILogger: 定义日志器 门面 接口
  • tSimpleLogger: 日志器门面, 实现 ILogger 接口, 外部应用 责任链模式 别离解决 Debug/Info/Error 申请
  • ILoggerFilter: 定义日志责任链节点的接口
  • tLoggerFilter: 日志责任链节点, 实现 ILoggerFilter 接口
  • tFileWriter: 具体负责日志输入, 实现 io.StringWriter 接口

单元测试

chain_responsibility_test.go

package behavioral_patterns

import (
    "learning/gooop/behavioral_patterns/chain"
    "testing"
)

func Test_ChainResponsibility(t *testing.T) {logger := chain.NewSimpleLogger()
    logger.Debug("a debug msg")
    logger.Info("an info msg")
    logger.Error("an error msg")
}

测试输入

$ go test -v chain_responsibility_test.go 
=== RUN   Test_ChainResponsibility
tFileWriter.WriteString, file=debug.log, msg=DEBUG a debug msg
tFileWriter.WriteString, file=info.log, msg=INFO an info msg
tFileWriter.WriteString, file=error.log, msg=ERROR an error msg
--- PASS: Test_ChainResponsibility (0.00s)
PASS
ok      command-line-arguments  0.002s

ILogger.go

定义日志器门面接口

package chain

type ILogger interface {Debug(msg string)
    Info(msg string)
    Error(msg string)
}

tSimpleLogger.go

日志器门面, 实现 ILogger 接口, 外部应用责任链模式别离解决 Debug/Info/Error 申请

package chain

type tSimpleLogger struct {chain ILoggerFilter}


func NewSimpleLogger() ILogger {vErrorLogger := newLoggerFilter(newFileWriter("error.log"), LEVEL_ERROR, nil)
    vInfoLogger := newLoggerFilter(newFileWriter("info.log"), LEVEL_INFO, nil)
    vDebugLogger := newLoggerFilter(newFileWriter("debug.log"), LEVEL_DEBUG, nil)

    vDebugLogger.Next(vInfoLogger)
    vInfoLogger.Next(vErrorLogger)

    return &tSimpleLogger {vDebugLogger,}
}

func (me *tSimpleLogger) Debug(msg string) {me.chain.Handle(LEVEL_DEBUG, msg)
}

func (me *tSimpleLogger) Info(msg string) {me.chain.Handle(LEVEL_INFO, msg)
}

func (me *tSimpleLogger) Error(msg string) {me.chain.Handle(LEVEL_ERROR, msg)
}

ILoggerFilter.go

定义日志责任链节点的接口

package chain

type LoggingLevel string
const LEVEL_DEBUG LoggingLevel  = "DEBUG"
const LEVEL_INFO LoggingLevel  = "INFO"
const LEVEL_ERROR LoggingLevel  = "ERROR"

type ILoggerFilter interface {Next(filter ILoggerFilter)
    Handle(level LoggingLevel, msg string)
}

tLoggerFilter.go

日志责任链节点, 实现 ILoggerFilter 接口

package chain

import (
    "fmt"
    "io"
)

type tLoggerFilter struct {
    writer io.StringWriter
    level LoggingLevel
    chain ILoggerFilter
}

func newLoggerFilter(writer io.StringWriter, level LoggingLevel, filter ILoggerFilter) ILoggerFilter {
    return &tLoggerFilter{writer, level, filter,}
}

func (me *tLoggerFilter) Next(filter ILoggerFilter) {me.chain = filter}

func (me *tLoggerFilter) Handle(level LoggingLevel, msg string) {
    if me.level == level {_,_ = me.writer.WriteString(fmt.Sprintf("%v %s", me.level, msg))

    } else {
        if me.chain != nil {me.chain.Handle(level, msg)
        }
    }
}

tFileWriter.go

具体负责日志输入, 实现 io.StringWriter 接口

package chain

import (
    "fmt"
    "io"
)

type tFileWriter struct {file string}

func newFileWriter(file string) io.StringWriter {
    return &tFileWriter{file,}
}

func (me *tFileWriter) WriteString(s string) (n int, e error) {fmt.Printf("tFileWriter.WriteString, file=%s, msg=%s\n", me.file, s)
    return len(s), nil
}

责任链模式小结

责任链模式的长处(1)将申请与处了解耦。(2)申请解决者(节点对象)只需关注本人感兴趣的申请进行解决即可,对于不感兴趣的申请,间接转发给下一个节点对象。(3)具备链式传递解决申请性能,申请发送者不须要通晓链路构造,只需期待申请处理结果即可。(4)链路构造灵便,能够通过扭转链路构造动静地新增或删减责任。(5)易于扩大新的申请解决类(节点),合乎开闭准则。责任链模式的毛病(1)责任链太长或者解决工夫过长,会影响整体性能。(2)如果节点对象存在循环援用,则会造成死循环,导致系统解体。(摘自 谭勇德 << 设计模式就该这样学 >>)

(end)

退出移动版