Go语言通过函数类型、闭包和接口嵌入实现装饰器模式:定义HandlerFunc统一契约,用高阶函数构造日志/认证等装饰器,支持链式调用;对结构体则通过接口+匿名字段嵌入实现可组合装饰;广泛应用于HTTP中间件及gRPC等框架。

Go 语言没有类和继承,也不支持注解(annotation)或装饰器语法(如 Python 的 @decorator),但可以通过函数式组合、接口抽象和高阶函数的方式,自然、简洁地实现装饰器模式的核心思想:在不修改原始对象的前提下,动态地为它添加行为。
用函数类型封装行为,实现“可装饰”的基础结构
装饰器的本质是“包装”——把一个行为(函数)包在另一个行为里。Go 中最直接的方式是定义统一的函数类型,作为被装饰和装饰者的契约:
例如,定义一个处理 HTTP 请求的通用函数类型:
type HandlerFunc func(http.ResponseWriter, *http.Request)
func (f HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {
f(w, r)
}
这样,任意符合 HandlerFunc 类型的函数都能被标准库的 http.ServeMux 使用,也为后续装饰留出空间。
立即学习“go语言免费学习笔记(深入)”;
通过闭包构造装饰器函数,叠加横切逻辑
装饰器本身是一个接受原函数并返回新函数的高阶函数。它不侵入原逻辑,只负责前置/后置/环绕操作:
- 日志装饰器:
func Logging(h HandlerFunc) HandlerFunc - 认证装饰器:
func Auth(h HandlerFunc) HandlerFunc - 超时装饰器:
func Timeout(d time.Duration) func(HandlerFunc) HandlerFunc(返回装饰器)
示例:一个简单的日志装饰器
func Logging(next HandlerFunc) HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Printf("START %s %s", r.Method, r.URL.Path)
next(w, r)
log.Printf("END %s %s", r.Method, r.URL.Path)
}
}
使用时只需链式调用:Logging(Auth(HomeHandler)),顺序即执行顺序(外层先触发)。
用接口+嵌入模拟“对象装饰”,增强可组合性
当需要装饰的是结构体实例(而非纯函数),可定义核心接口,再用匿名字段嵌入原对象,实现 Go 风格的“装饰器结构体”:
type Service interface {
Do() string
}
type ConcreteService struct{}
func (s ConcreteService) Do() string { return "work" }
type LoggingService struct {
Service // 嵌入,复用原有方法
}
func (s LoggingService) Do() string {
log.Println("before")
result := s.Service.Do()
log.Println("after")
return result
}
这种方式清晰表达了“扩展而非修改”,且支持多层嵌套(如 LoggingService{AuthService{ConcreteService{}}})。
结合中间件模式,用于 Web 和 RPC 场景
实际项目中,装饰器常以中间件形式落地。标准库 http.Handler 接口天然支持链式装饰:
- 用
http.HandlerFunc统一类型 - 每个中间件返回新的
http.Handler - 用
http.Handler的ServeHTTP方法完成调用链
典型中间件链写法:
handler := Logging(Auth(Recover(PanicHandler)))
http.Handle("/api", handler)
这种模式也被 gRPC、Echo、Gin 等框架广泛采用,本质就是装饰器模式的工程化延伸。










