跳到主要内容

装饰器模式

简介

装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许你动态地向一个对象添加新的行为或职责,而无需修改其原始代码。这种模式遵循开放/封闭原则(对扩展开放,对修改封闭)。

核心思想是创建一个“包装器”(Decorator)对象,这个包装器持有对原始“组件”(Component)对象的引用。包装器和组件对象实现相同的接口。当调用包装器的方法时,它可以在将调用委托给原始组件对象之前或之后(或两者都)执行额外的操作。多个装饰器可以层层嵌套,为对象添加多重功能。

可以把它想象成给一个物体穿衣服:

  1. 组件 (Component): 基础的物体(比如一个人)。
  2. 具体组件 (Concrete Component): 具体的物体实例(比如张三)。
  3. 装饰器 (Decorator): 衣服的抽象概念,知道自己要装饰哪个物体。
  4. 具体装饰器 (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)
}