当前位置: 首页 > news >正文

Go 装饰器模式学习文档

目录

  1. 装饰器模式简介
  2. Go 中实现装饰器的方式
  3. 使用 logrus 记录日志
  4. 示例:为函数添加日志装饰器
  5. 多个装饰器的组合
  6. 最佳实践
  7. 总结

1. 装饰器模式简介

装饰器模式是一种结构型设计模式,它允许向一个对象动态地添加新的行为,而不需要修改该对象的基类或使用继承。装饰器模式通过创建一个包装对象来包裹真实的对象,提供额外的功能。

在 Go 中,装饰器模式通常通过函数式编程的方式实现,利用 Go 的函数作为一等公民的特性,我们可以创建高阶函数来包装其他函数,添加额外的行为。

装饰器模式的优点:

  • 在不改变原有对象结构的情况下,动态地添加功能
  • 遵循开闭原则(对扩展开放,对修改关闭)
  • 可以灵活地组合多个装饰器

2. Go 中实现装饰器的方式

在 Go 中,装饰器通常是通过高阶函数实现的。高阶函数是指接受函数作为参数或返回函数的函数。下面是一个简单的装饰器示例:

// 装饰器函数,接受一个函数并返回一个包装后的函数
func decorator(f func()) func() {return func() {fmt.Println("装饰器:函数调用前")f()fmt.Println("装饰器:函数调用后")}
}func hello() {fmt.Println("Hello, World!")
}func main() {// 使用装饰器包装hello函数decoratedHello := decorator(hello)decoratedHello()
}

输出:

装饰器:函数调用前
Hello, World!
装饰器:函数调用后

3. 使用 logrus 记录日志

在 Go 中,logrus 是一个流行的结构化日志库,提供了丰富的功能。首先,我们需要安装 logrus

go get github.com/sirupsen/logrus

下面是一个简单的 logrus 使用示例:

package mainimport ("github.com/sirupsen/logrus"
)func main() {// 创建一个新的logger实例logger := logrus.New()// 设置日志级别logger.SetLevel(logrus.DebugLevel)// 设置日志格式为JSONlogger.SetFormatter(&logrus.JSONFormatter{})// 记录不同级别的日志logger.Debug("这是一条调试信息")logger.Info("这是一条普通信息")logger.Warn("这是一条警告信息")logger.Error("这是一条错误信息")// 记录带字段的日志logger.WithFields(logrus.Fields{"event": "test","topic": "logging",}).Info("这是一条带字段的日志")
}

4. 示例:为函数添加日志装饰器

现在,我们将结合装饰器模式和 logrus 来创建一个日志装饰器,用于记录函数的调用信息。

package mainimport ("fmt""time""github.com/sirupsen/logrus"
)// 创建一个logger实例
var logger = logrus.New()// 初始化logger
func init() {// 设置日志级别logger.SetLevel(logrus.DebugLevel)// 设置日志格式为JSONlogger.SetFormatter(&logrus.JSONFormatter{})
}// 日志装饰器
func logDecorator(name string, f func()) func() {return func() {start := time.Now()logger.WithFields(logrus.Fields{"function": name,"event":    "start","time":     start.Format(time.RFC3339),}).Info("Function call started")f()duration := time.Since(start)logger.WithFields(logrus.Fields{"function": name,"event":    "end","duration": duration.String(),}).Info("Function call completed")}
}// 示例函数1
func processData() {logger.Info("Processing data...")time.Sleep(100 * time.Millisecond)logger.Info("Data processed successfully")
}// 示例函数2
func saveToDatabase() {logger.Info("Saving to database...")time.Sleep(150 * time.Millisecond)logger.Info("Data saved successfully")
}func main() {// 使用装饰器包装函数decoratedProcessData := logDecorator("processData", processData)decoratedSaveToDatabase := logDecorator("saveToDatabase", saveToDatabase)// 调用装饰后的函数decoratedProcessData()decoratedSaveToDatabase()
}

输出示例(JSON格式):

{"event":"start","function":"processData","level":"info","msg":"Function call started","time":"2023-05-20T10:00:00+08:00"}
{"level":"info","msg":"Processing data..."}
{"level":"info","msg":"Data processed successfully"}
{"duration":"100.123ms","event":"end","function":"processData","level":"info","msg":"Function call completed"}
{"event":"start","function":"saveToDatabase","level":"info","msg":"Function call started","time":"2023-05-20T10:00:00+08:00"}
{"level":"info","msg":"Saving to database..."}
{"level":"info","msg":"Data saved successfully"}
{"duration":"150.456ms","event":"end","function":"saveToDatabase","level":"info","msg":"Function call completed"}

5. 多个装饰器的组合

装饰器模式的一个强大之处在于可以组合多个装饰器,每个装饰器负责一个特定的功能。下面我们创建多个装饰器,并演示如何组合它们:

package mainimport ("fmt""os""time""github.com/sirupsen/logrus"
)// 创建一个logger实例
var logger = logrus.New()// 初始化logger
func init() {// 设置日志级别logger.SetLevel(logrus.DebugLevel)// 设置日志格式为JSONlogger.SetFormatter(&logrus.JSONFormatter{})// 设置输出到标准输出logger.SetOutput(os.Stdout)
}// 日志装饰器
func logDecorator(name string) func(func()) func() {return func(f func()) func() {return func() {start := time.Now()logger.WithFields(logrus.Fields{"function": name,"event":    "start","time":     start.Format(time.RFC3339),}).Info("Function call started")f()duration := time.Since(start)logger.WithFields(logrus.Fields{"function": name,"event":    "end","duration": duration.String(),}).Info("Function call completed")}}
}// 计时装饰器
func timingDecorator(name string) func(func()) func() {return func(f func()) func() {return func() {start := time.Now()logger.WithField("function", name).Info("Timing started")f()duration := time.Since(start)logger.WithFields(logrus.Fields{"function": name,"duration": duration.String(),}).Info("Timing completed")}}
}// 错误处理装饰器
func errorHandlingDecorator(name string) func(func()) func() {return func(f func()) func() {return func() {defer func() {if r := recover(); r != nil {logger.WithFields(logrus.Fields{"function": name,"error":    r,}).Error("Function panicked")}}()f()}}
}// 示例函数
func processData() {logger.Info("Processing data...")time.Sleep(100 * time.Millisecond)logger.Info("Data processed successfully")
}// 可能出错的函数
func riskyOperation() {logger.Info("Starting risky operation...")time.Sleep(50 * time.Millisecond)// 模拟一个错误panic("something went wrong")
}// 装饰器工厂函数,用于组合多个装饰器
func decorate(f func(), decorators ...func(func()) func()) func() {decorated := f// 按照相反的顺序应用装饰器,这样第一个装饰器将是最外层的for i := len(decorators) - 1; i >= 0; i-- {decorated = decorators[i](decorated)}return func() {decorated()}
}func main() {// 组合多个装饰器decoratedProcessData := decorate(processData,logDecorator("processData"),timingDecorator("processData"),errorHandlingDecorator("processData"),)decoratedRiskyOperation := decorate(riskyOperation,logDecorator("riskyOperation"),timingDecorator("riskyOperation"),errorHandlingDecorator("riskyOperation"),)// 调用装饰后的函数decoratedProcessData()decoratedRiskyOperation()
}

输出示例(JSON格式):

{"event":"start","function":"processData","level":"info","msg":"Function call started","time":"2023-05-20T10:00:00+08:00"}
{"function":"processData","level":"info","msg":"Timing started"}
{"level":"info","msg":"Processing data..."}
{"level":"info","msg":"Data processed successfully"}
{"duration":"100.123ms","function":"processData","level":"info","msg":"Timing completed"}
{"duration":"100.123ms","event":"end","function":"processData","level":"info","msg":"Function call completed"}
{"event":"start","function":"riskyOperation","level":"info","msg":"Function call started","time":"2023-05-20T10:00:00+08:00"}
{"function":"riskyOperation","level":"info","msg":"Timing started"}
{"level":"info","msg":"Starting risky operation..."}
{"duration":"50.456ms","function":"riskyOperation","level":"info","msg":"Timing completed"}
{"error":"something went wrong","function":"riskyOperation","level":"error","msg":"Function panicked"}
{"duration":"50.456ms","event":"end","function":"riskyOperation","level":"info","msg":"Function call completed"}

6. 最佳实践

  1. 单一职责原则:每个装饰器应该只负责一个特定的功能,如日志记录、计时、错误处理等。

  2. 装饰器顺序:装饰器的应用顺序很重要。通常,最外层的装饰器最先执行,最内层的装饰器最后执行。

  3. 性能考虑:装饰器会引入额外的开销,特别是在高频调用的函数上。应该权衡装饰器带来的价值和性能开销。

  4. 错误处理:确保装饰器能够正确处理和传播错误,避免掩盖原始错误。

  5. 上下文信息:在装饰器中记录足够的上下文信息,以便于调试和监控。

  6. 可配置性:使装饰器可配置,例如通过选项模式允许用户自定义日志级别、格式等。

  7. 测试:为装饰器编写单元测试,确保它们在各种情况下都能正常工作。

7. 总结

Go 中的装饰器模式是一种强大的技术,它允许我们以非侵入性的方式为函数添加额外的功能。通过结合 logrus 这样的日志库,我们可以轻松地实现日志记录、性能监控、错误处理等功能。

装饰器模式的主要优点:

  • 不需要修改原有函数即可添加新功能
  • 可以灵活地组合多个装饰器
  • 遵循开闭原则,对扩展开放,对修改关闭

在实际应用中,装饰器模式常用于:

  • 日志记录
  • 性能监控和计时
  • 认证和授权
  • 缓存
  • 错误处理和恢复
  • 事务管理

通过合理地使用装饰器模式,我们可以使代码更加模块化、可维护和可扩展。


文章转载自:

http://2OyYSOvU.cwyfs.cn
http://fRqt8Vow.cwyfs.cn
http://kxHdZWHf.cwyfs.cn
http://bBJu4TAh.cwyfs.cn
http://7rcNrvQJ.cwyfs.cn
http://gwlMqVKQ.cwyfs.cn
http://UL9jLfDp.cwyfs.cn
http://gNf4I4um.cwyfs.cn
http://WVLhr6jA.cwyfs.cn
http://xB0Kj3La.cwyfs.cn
http://OeWRRPKk.cwyfs.cn
http://jHT0Dlfc.cwyfs.cn
http://IlbQEUBh.cwyfs.cn
http://f6Z7n6wn.cwyfs.cn
http://iYD1mlBO.cwyfs.cn
http://ysz7J8IM.cwyfs.cn
http://iafT5Fv4.cwyfs.cn
http://J7rbAt5k.cwyfs.cn
http://X8Po6aPt.cwyfs.cn
http://QtBPy6Ay.cwyfs.cn
http://JPd8t3lt.cwyfs.cn
http://lOhkzwxb.cwyfs.cn
http://U8z2wQFW.cwyfs.cn
http://cEcxa9OW.cwyfs.cn
http://QgvtHkMV.cwyfs.cn
http://TkhRt4iU.cwyfs.cn
http://4Aj5JXa2.cwyfs.cn
http://D99JCFxV.cwyfs.cn
http://i3mOXD35.cwyfs.cn
http://U3qQvcgz.cwyfs.cn
http://www.dtcms.com/a/374660.html

相关文章:

  • 20.44 QLoRA调参秘籍:零成本实现7B模型微调,参数黄金配比全解析(附3090实战方案)
  • Ubuntu 22.04 安装 Docker Compose 最新最简单完整指南​
  • 网络原理——传输层协议UDP
  • 从Java全栈开发到云原生实践:一次真实面试的深度剖析
  • 更换libc.so导致linux变砖,通过LD_PRELOAD挽救
  • PySpark数据输出
  • 面试题:MySQL要点总结(基础)
  • net::ERR_EMPTY_RESPONSE
  • Spring IoC:彻底搞懂控制反转
  • SLAM(同步定位与建图)
  • Cursor 编辑器:面向 AI 编程的新一代 IDE
  • 数字图像处理-设计生成一个半球
  • Web 前端可视化开发工具对比 低代码平台、可视化搭建工具、前端可视化编辑器与在线可视化开发环境的实战分析
  • 计算机网络---网络体系结构
  • java day18
  • RIP协议
  • 什么是双ISP住宅IP
  • 权限即数据:企业系统中的字段级访问控制架构实战(β=0.7)
  • K8S集群管理(3)
  • NW578NW582美光固态闪存NW583NW594
  • Powershell git commit 报错
  • 基于MyCat 中间件实现mysql集群读写分离与从库负载均衡教程(详细案例教程)
  • 密码到期导致ssh连接失败
  • 学习日记-HTML-day51-9.9
  • 硬件开发2-汇编2(ARMv7-A)
  • 基于mybatis-plus动态数据源实现mysql集群读写分离和从库负载均衡教程(详细案例)
  • Elasticsearch面试精讲 Day 14:数据写入与刷新机制
  • TDengine 选择函数 LAST_ROW() 用户手册
  • Flink 状态管理的核心能力
  • Hive实战(三)