Go 装饰器模式
外观
Go装饰器模式[编辑 | 编辑源代码]
装饰器模式(Decorator Pattern)是一种结构型设计模式,允许在不修改原有对象的情况下动态地扩展其功能。在Go语言中,由于缺乏类继承机制,装饰器模式通常通过组合和接口来实现。它特别适用于需要为对象添加额外行为而又不改变其结构的场景。
基本概念[编辑 | 编辑源代码]
装饰器模式的核心思想是:
- 定义一个基础接口,表示被装饰对象的类型。
- 创建具体的实现类,实现基础接口。
- 创建装饰器结构体,同样实现基础接口,并包含一个基础接口类型的成员变量。
- 在装饰器的方法中,调用成员变量的方法,并在其前后添加额外的行为。
数学上可以表示为:若原始函数为,装饰后的函数为,其中是装饰逻辑。
Go实现示例[编辑 | 编辑源代码]
以下是一个简单的Go装饰器示例,展示如何为函数添加日志功能:
package main
import (
"fmt"
"time"
)
// 基础接口
type Worker interface {
DoWork() string
}
// 具体实现
type BasicWorker struct{}
func (b *BasicWorker) DoWork() string {
return "Basic work done"
}
// 日志装饰器
type LoggingDecorator struct {
worker Worker
}
func (l *LoggingDecorator) DoWork() string {
start := time.Now()
result := l.worker.DoWork()
end := time.Now()
fmt.Printf("Work started at: %v\n", start)
fmt.Printf("Work result: %s\n", result)
fmt.Printf("Work ended at: %v\n", end)
fmt.Printf("Duration: %v\n", end.Sub(start))
return result
}
func main() {
basic := &BasicWorker{}
decorated := &LoggingDecorator{worker: basic}
fmt.Println("Basic worker:")
fmt.Println(basic.DoWork())
fmt.Println("\nDecorated worker:")
decorated.DoWork()
}
输出结果:
Basic worker: Basic work done Decorated worker: Work started at: 2023-05-15 10:30:00.123456 +0800 CST m=+0.000000001 Work result: Basic work done Work ended at: 2023-05-15 10:30:00.123457 +0800 CST m=+0.000000002 Duration: 1ns
装饰器链[编辑 | 编辑源代码]
可以创建多个装饰器并将它们链接起来,每个装饰器添加不同的功能:
// 计时装饰器
type TimingDecorator struct {
worker Worker
}
func (t *TimingDecorator) DoWork() string {
start := time.Now()
result := t.worker.DoWork()
fmt.Printf("Operation took: %v\n", time.Since(start))
return result
}
func main() {
basic := &BasicWorker{}
decorated := &TimingDecorator{
worker: &LoggingDecorator{worker: basic},
}
decorated.DoWork()
}
函数装饰器[编辑 | 编辑源代码]
在Go中,函数是一等公民,可以直接装饰函数:
type WorkerFunc func() string
func Logging(f WorkerFunc) WorkerFunc {
return func() string {
fmt.Println("Before execution")
result := f()
fmt.Println("After execution")
return result
}
}
func main() {
basic := func() string {
return "Basic function work"
}
decorated := Logging(basic)
fmt.Println(decorated())
}
实际应用场景[编辑 | 编辑源代码]
1. 日志记录:在不修改业务逻辑的情况下添加日志 2. 性能监控:测量函数执行时间 3. 缓存:为昂贵操作添加缓存层 4. 认证/授权:在执行业务逻辑前检查权限 5. 重试机制:为可能失败的操作添加自动重试
HTTP中间件案例[编辑 | 编辑源代码]
HTTP中间件是装饰器模式的典型应用:
package main
import (
"fmt"
"net/http"
)
type Handler func(http.ResponseWriter, *http.Request)
func LoggingMiddleware(next Handler) Handler {
return func(w http.ResponseWriter, r *http.Request) {
fmt.Printf("Request: %s %s\n", r.Method, r.URL.Path)
next(w, r)
}
}
func AuthMiddleware(next Handler) Handler {
return func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Authorization") == "" {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
next(w, r)
}
}
func mainHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Main handler executed")
}
func main() {
handler := LoggingMiddleware(AuthMiddleware(mainHandler))
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
类图表示[编辑 | 编辑源代码]
优缺点[编辑 | 编辑源代码]
优点:
- 比继承更灵活,可以在运行时添加或移除功能
- 符合开闭原则,无需修改现有代码就能扩展功能
- 可以组合多个装饰器实现复杂功能
缺点:
- 可能引入许多小类,增加系统复杂度
- 装饰器栈过深可能影响性能
- 调试可能变得困难,因为行为分布在多个装饰器中
总结[编辑 | 编辑源代码]
Go装饰器模式提供了一种强大的方式来扩展对象功能而不修改其结构。通过组合和接口,Go开发者可以实现类似其他语言中通过继承获得的功能扩展。这种模式特别适合需要动态添加功能的场景,如中间件、日志、监控等。理解装饰器模式有助于编写更灵活、可维护的Go代码。