11

手撸golang 结构型设计模式 装饰器模式

 4 years ago
source link: https://studygolang.com/articles/33130
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

手撸golang 结构型设计模式 装饰器模式

缘起

最近复习设计模式

拜读谭勇德的<<设计模式就该这样学>>

本系列笔记拟采用golang练习之

装饰器模式

装饰器模式(Decorator Pattern)也叫作包装器模式(Wrapper Pattern),指在不改变原有对象的基础上,动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活,属于结构型设计模式。

_

装饰器模式vs代理模式

  • 装饰器模式就是代理模式的一个特殊应用。
  • 装饰器模式强调自身功能的扩展。
  • 代理模式强调对代理过程的控制。

_

场景

  • 某业务系统, 输出日志信息到文件
  • 现要求集成第三方日志分析服务
  • 日志服务需要json格式的日志流
  • 因此需要改造原日志输出的实现, 实现json格式输出功能

设计

  • ILogger: 定义日志器接口
  • ILoggerFactory: 定义日志器工厂
  • tConsoleLogger: 默认的日志器实现, 使用console输出日志消息
  • tConsoleLoggerFactory: 默认的日志器工厂
  • tJsonLogger: 使用json格式输出日志消息的日志器. 使用装饰器模式, 增加了将日志消息格式化为json的功能.
  • tJsonLoggerFactory: json日志器的工厂

单元测试 - decorator_pattern_test.go

通过切换日志工厂, 测试日志输出的不同效果

package structural_patterns

import (
    "learning/gooop/structural_patterns/decorator"
    "testing"
)

func Test_DecoratorPattern(t *testing.T) {
    fnTestLogger := func(factory decorator.ILoggerFactory) {
        logger := factory.GetLogger("testing.Test_DecoratorPattern")
        logger.Debug("This is a DEBUG msg")
        logger.Info("This is an INFO msg")
    }

    fnTestLogger(decorator.ConsoleLoggerFactory)
    fnTestLogger(decorator.JsonLoggerFactory)
}

测试输出

$ go test -v decorator_pattern_test.go 
=== RUN   Test_DecoratorPattern
2021-02-02T15:50:10 [testing.Test_DecoratorPattern] DEBUG This is a DEBUG msg
2021-02-02T15:50:10 [testing.Test_DecoratorPattern] INFO This is an INFO msg
2021-02-02T15:50:10 [testing.Test_DecoratorPattern] DEBUG {
  "Time": "2021-02-02T15:50:10",
  "Level": "DEBUG",
  "Msg": "This is a DEBUG msg"
}
2021-02-02T15:50:10 [testing.Test_DecoratorPattern] DEBUG {
  "Time": "2021-02-02T15:50:10",
  "Level": "INFO",
  "Msg": "This is an INFO msg"
}
--- PASS: Test_DecoratorPattern (0.00s)
PASS
ok      command-line-arguments  0.002s

ILogger.go

定义日志器接口

package decorator

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

ILoggerFactory.go

定义日志器工厂

package decorator

type ILoggerFactory interface {
    GetLogger(name string) ILogger
}

tConsoleLogger.go

默认的日志器实现, 使用console输出日志消息

package decorator

import (
    "fmt"
    "time"
)

type tConsoleLogger struct {
    name string
}


func nowString() string {
    return time.Now().Format("2006-01-02T15:04:05")
}

func (me *tConsoleLogger) log(msg string, level string) {
    fmt.Printf("%s [%s] %s %s\n", nowString(), me.name, level, msg)
}

func (me *tConsoleLogger) Debug(msg string) {
    me.log(msg, "DEBUG")
}

func (me *tConsoleLogger) Info(msg string) {
    me.log(msg, "INFO")
}


func (me *tConsoleLogger) Warn(msg string) {
    me.log(msg, "WARN")
}


func (me *tConsoleLogger) Error(msg string) {
    me.log(msg, "ERROR")
}

tConsoleLoggerFactory.go

默认的日志器工厂

package decorator

type tConsoleLoggerFactory struct {
}

func newConsoleLoggerFactory() ILoggerFactory {
    return &tConsoleLoggerFactory{}
}

func (me *tConsoleLoggerFactory) GetLogger(name string) ILogger {
    return &tConsoleLogger{
        name,
    }
}

var ConsoleLoggerFactory = newConsoleLoggerFactory()

tJsonLogger.go

使用json格式输出日志消息的日志器. 使用装饰器模式, 增加了将日志消息格式化为json的功能.

package decorator

import (
    "encoding/json"
)

type tJsonLogger struct {
    sName string
    mLogger ILogger
}


type tJsonMsg struct {
    Time string
    Level string
    Msg string
}

func (me *tJsonMsg) String() string {
    j, e := json.MarshalIndent(me, "", "  ")
    if e != nil {
        return ""
    }
    return string(j)
}

func newJsonLogger(name string, logger ILogger) ILogger {
    return &tJsonLogger{
        name,
        logger,
    }
}

func (me *tJsonLogger) toJson(msg string, level string) string {
    j := &tJsonMsg{
        Time: nowString(),
        Level: level,
        Msg: msg,
    }
    return j.String()
}

func (me *tJsonLogger) Debug(msg string) {
    me.mLogger.Debug(me.toJson(msg, "DEBUG"))
}

func (me *tJsonLogger) Info(msg string) {
    me.mLogger.Debug(me.toJson(msg, "INFO"))
}

func (me *tJsonLogger) Warn(msg string) {
    me.mLogger.Debug(me.toJson(msg, "WARN"))
}

func (me *tJsonLogger) Error(msg string) {
    me.mLogger.Debug(me.toJson(msg, "ERROR"))
}

tJsonLoggerFactory.go

json日志器的工厂

package decorator

type tJsonLoggerFactory struct {
}

func newJsonLoggerFactory() ILoggerFactory {
    return &tJsonLoggerFactory{}
}

func (me *tJsonLoggerFactory) GetLogger(name string) ILogger {
    logger := ConsoleLoggerFactory.GetLogger(name)
    return newJsonLogger(name, logger)
}

var JsonLoggerFactory = newJsonLoggerFactory()

装饰器模式小结

装饰器模式的优点

(1)装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态地给一个对象扩展功能,即插即用。

(2)通过使用不同装饰类及这些装饰类的排列组合,可以实现不同效果。

(3)装饰器模式完全遵守开闭原则。

装饰器模式的缺点

(1)会出现更多的代码、更多的类,增加程序的复杂性。

(2)动态装饰在多层装饰时会更复杂。

_

(end)

有疑问加站长微信联系(非本文作者)

eUjI7rn.png!mobile

Recommend

  • 10

    手撸golang 结构型设计模式 门面模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 门面模式 门面模式(Facade Patte...

  • 10

    手撸golang 结构型设计模式 组合模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 组合模式 组合模式(Composite...

  • 16

    手撸golang 行为型设计模式 委派模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 委派模式 委派模式(Delegate...

  • 5

    手撸golang 行为型设计模式 策略模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 策略模式 策略模式(Strategy Patter...

  • 18

    手撸golang 行为型设计模式 责任链模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 责任链模式 责任链模式(Chain of...

  • 9

    手撸golang 行为型设计模式 迭代器模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 迭代器模式 迭代器模式(Iterator...

  • 11

    手撸golang 行为型设计模式 备忘录模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 备忘录模式 备忘录模式(Memento P...

  • 8

    结构型设计模式 创建型设计模式主要是为了解决创建对象的问题,而结构型设计模式则是为了解决已有对象的使用问题。 适配器模式 适配器模式比较好理解,因为在我们的日常生活中就很常见,如耳机转换线、充电器适配器、插座等,举个最常...

  • 5
    • hongker.github.io 2 years ago
    • Cache

    Golang设计模式(02)-结构型模式(上)

    前面介绍了设计模式中的建造型模式,这篇介绍结构型模式的一部分。主要是适配器模式、装饰器模式、代理模式的设计说明 描述将类和对象结合在一起,形成一个更强大的结构。 类结构型模式:关心类的组合,由多个类...

  • 9

      如果希望动态给某个类添加一些属性或者方法,但是你又不希望这个类派生的对象受到影响,那么装饰器模式就可以给你带来这样的体验。 它的定义就是在不改变原对象的基础上,通过对其进行包装拓...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK