Go可通过接口、结构体嵌入和高阶函数实现装饰器模式:定义统一接口(如Processor),用嵌入接口的结构体(如LoggingProcessor)重写方法添加逻辑,支持链式组合;也可用函数式装饰器(如WithLogging)简化构造,动态增强行为。

Go 语言本身不支持类和继承,也没有原生的“装饰器”语法(如 Python 的 @decorator),但完全可以通过组合、接口和高阶函数等方式,**实现装饰器模式的核心思想:在不修改原有对象的前提下,动态地添加职责或行为**。关键在于利用 Go 的接口抽象能力和结构体嵌套机制。
用接口定义统一行为契约
装饰器模式的前提是所有被装饰者和装饰器都实现同一接口。这是实现多态和动态替换的基础。
例如定义一个基础的处理器接口:
type Processor interface {Process(data string) string
}
原始实现(被装饰对象):
立即学习“go语言免费学习笔记(深入)”;
type BaseProcessor struct{}func (b BaseProcessor) Process(data string) string {
return "base: " + data
}
用结构体嵌入实现装饰器(推荐方式)
Go 中最自然、最符合工程实践的方式是:**定义一个装饰器结构体,内嵌被装饰的接口(或具体类型),并重写部分方法,在调用原方法前后插入新逻辑**。
例如添加日志和计时功能:
Processor // 嵌入接口,获得组合能力
}
func (l LoggingProcessor) Process(data string) string {
fmt.Println("→ Start processing:", data)
result := l.Processor.Process(data)
fmt.Println("← Done. Result:", result)
return result
}
type TimingProcessor struct {
Processor
}
func (t TimingProcessor) Process(data string) string {
start := time.Now()
result := t.Processor.Process(data)
fmt.Printf("[%.2fms] Processed\n", float64(time.Since(start).Microseconds())/1000)
return result
}
链式组合多个装饰器
因为每个装饰器都实现了 `Processor` 接口,所以可以层层包装,形成运行时可配置的行为链:
base := BaseProcessor{}logged := LoggingProcessor{Processor: base}
timed := TimingProcessor{Processor: logged}
// 调用时自动触发日志 → 计时 → 基础处理
timed.Process("hello")
输出顺序为:
→ Start processing: hello
[0.02ms] Processed
← Done. Result: base: hello
你还可以按需交换顺序(比如先计时再日志),或只使用其中一部分,完全动态。
用函数式装饰器简化构造(进阶技巧)
如果想更轻量、避免定义大量结构体,可用函数类型封装装饰逻辑:
type ProcessorFunc func(string) stringfunc (f ProcessorFunc) Process(data string) string {
return f(data)
}
// 装饰器工厂函数
func WithLogging(next Processor) Processor {
return ProcessorFunc(func(data string) string {
fmt.Println("LOG: input =", data)
out := next.Process(data)
fmt.Println("LOG: output =", out)
return out
})
}
func WithUppercase(next Processor) Processor {
return ProcessorFunc(func(data string) string {
return strings.ToUpper(next.Process(data))
})
}
使用方式简洁直观:
p := WithUppercase(WithLogging(BaseProcessor{}))p.Process("go") // 输出全大写,并带日志
不复杂但容易忽略:装饰器要真正“透明”,必须确保所有公共方法都通过嵌入/委托暴露;若原接口后续增加方法,装饰器也要同步适配——这是组合优于继承时需承担的维护责任。










