Go可通过接口、结构体嵌入和高阶函数实现装饰器模式:定义统一接口(如Processor),用嵌入接口的结构体(如LoggingProcessor)重写方法添加逻辑,支持链式组合;也可用函数式装饰器(如WithLogging)简化构造,动态增强行为。
Go 语言本身不支持类和继承,也没有原生的“装饰器”语法(如 Python 的
),但完全可以通过组合、接口和高阶函数等方式,**实现装饰器模式的核心思想:在不修改原有对象的前提下,动态地添加职责或行为**。关键在于利用 Go 的接口抽象能力和结构体嵌套机制。
用接口定义统一行为契约
装饰器模式的前提是所有被装饰者和装饰器都实现同一接口。这是实现多态和动态替换的基础。
例如定义一个基础的
处理器
接口:
type Processor interface {Process(data string) string}
原始实现(被装饰对象):
立即学习
“
go语言免费学习笔记(深入)
”;
type BaseProcessor struct{}func (b BaseProcessor) Process(data string) string {return "base: " + data}
用结构体嵌入实现装饰器(推荐方式)
Go 中最自然、最符合工程实践的方式是:**定义一个装饰器结构体,内嵌被装饰的接口(或具体类型),并重写部分方法,在调用原方法前后插入新逻辑**。
例如添加日志和计时功能:
Python 3.14.3
微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。
下载
type LoggingProcessor struct {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") // 输出全大写,并带日志
不复杂但容易忽略:装饰器要真正“透明”,必须确保所有公共方法都通过嵌入/委托暴露;若原接口后续增加方法,装饰器也要同步适配——这是组合优于继承时需承担的维护责任。
@decorator