装饰器模式
简介
装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许你动态地向一个对象添加新的行为或职责,而无需修改其原始代码。这种模式遵循开放/封闭原则(对扩展开放,对修改封闭)。
核心思想是创建一个“包装器”(Decorator)对象,这个包装器持有对原始“组件”(Component)对象的引用。包装器和组件对象实现相同的接口。当调用包装器的方法时,它可以在将调用委托给原始组件对象之前或之后(或两者都)执行额外的操作。多个装饰器可以层层嵌套,为对象添加多重功能。
可以把它想象成给一个物体穿衣服:
- 组件 (Component): 基础的物体(比如一个人)。
- 具体组件 (Concrete Component): 具体的物体 实例(比如张三)。
- 装饰器 (Decorator): 衣服的抽象概念,知道自己要装饰哪个物体。
- 具体装饰器 (Concrete Decorator): 具体的衣服(比如一件毛衣、一件外套)。
常见使用场景
- HTTP中间件,这是Go中最经典的装饰器模式应用。
net/http
包中的Handler
接口就是一个很好的例子。中间件函数(装饰器)接收一个http.Handler
,并返回一个新的http.Handler
。这个新的处理器会在调用原始处理器之前或之后执行一些逻辑,如:- 日志记录 (Logging): 记录每个请求的详细信息。
- 认证/授权 (Authentication/Authorization): 检查用户凭证或权限。
- 请求压缩 (Compression): 对响应进行gzip压缩。
- 请求追踪/度量 (Tracing/Metrics): 记录请求耗时、状态码等。
- Panic 恢复 (Panic Recovery): 捕获处理过程中的panic,防止服务崩溃。
- 添加请求头/上下文 (Adding Headers/Context): 向请求或上下文中注入信息。
- 日志增强,例如添加时间戳、格式包装
- IO流包装
- 函数链式调用增强
- 缓存包装(给接口添加缓存逻辑)
优点
- 避免子类爆炸,灵活组合功能
- 符合开闭原则(对扩展开放,对修改封闭)
- 可以按需组合不同功能
缺点
- 多层包装,调试排查复杂
- 多层调用堆栈,可能影响性能
- 装饰器链可能难以理解
示例代码
Python有装饰器的语法糖,可以直接去查看Python中装饰器的用法。
Simple
Go
package decorator
import "fmt"
type Component interface {
Operation()
}
type ConcreteComponent struct {}
func (c *ConcreteComponent) Operation() {
fmt.Println("Concrete Component Operation")
}
type Decorator struct {
component Component
}
func (d *Decorator) SetComponent(c Component) {
d.component = c
}
func (d *Decorator) Operation() {
if d.component != nil {
d.component.Operation()
}
}
type DecoratorA struct {
Decorator
}
func (d *DecoratorA) Operation() {
d.component.Operation()
d.IndependentMethod()
}
// 具体装饰器A的扩展方法
func (d *DecoratorA) IndependentMethod() {
fmt.Println("DecoratorA independent method")
}
type DecoratorB struct {
Decorator
}
func (d *DecoratorB) Operation() {
d.component.Operation()
fmt.Println(d.String())
}
func (d *DecoratorB) String() string {
return "DecoratorB extend method"
}
client
package decorator
import "testing"
func TestDecorator(t *testing.T) {
concretComponent := &ConcreteComponent{}
decoratorA := &DecoratorA{}
decoratorB := &DecoratorB{}
decoratorA.SetComponent(concretComponent)
decoratorB.SetComponent(decoratorA)
decoratorB.Operation()
}
output
Concrete Component Operation
DecoratorA independent method
DecoratorB extend method
HTTP中间件
Go
package main
import (
"fmt"
"net/http"
"time"
)
// Component:核心功能,所有处理函数都符合 http.Handler
func HelloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, World!")
}
// Decorator:日志装饰器
func LoggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
fmt.Printf("Started %s %s\n", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
fmt.Printf("Completed in %v\n", time.Since(start))
})
}
// Decorator:认证装饰器
func AuthMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("X-Auth-Token")
if token != "secret" {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
})
}
func main() {
var handler http.Handler = http.HandlerFunc(HelloHandler)
// 使用装饰器模式,动态组合功能
handler = LoggingMiddleware(handler)
handler = AuthMiddleware(handler)
http.Handle("/", handler)
fmt.Println("Server running on :8080")
http.ListenAndServe(":8080", nil)
}