装饰者模式通过接口和组合实现功能扩展,定义统一接口后,使用包装器在不修改原对象的情况下动态添加日志、缓存等行为,支持链式叠加多个装饰器,适用于中间件、监控、事务等场景,保持职责单一与类型一致。

在 Go 语言中,装饰者模式是一种灵活扩展结构体功能的方式,无需修改原始类型代码。它通过组合和接口实现,在运行时动态添加行为,非常适合日志、权限校验、缓存等横切关注点的处理。
理解装饰者模式的核心思想
装饰者模式允许你将对象放入一系列包装器中,每层包装器都可以附加额外的行为或责任。与继承不同,装饰者更灵活,可以在不改变原类型的前提下增强功能。
Go 没有类和继承,但通过接口和结构体嵌套可以很好地实现这一模式。关键在于:
- 定义一个统一的行为接口
- 原始实现满足该接口
- 装饰器也实现相同接口,并持有对原对象的引用
- 调用时可在前后插入自定义逻辑
通过实例实现日志装饰器
假设我们有一个用户服务接口,提供获取用户信息的方法:
立即学习“go语言免费学习笔记(深入)”;
type UserService interface {
GetUser(id int) string
}
type userService struct{}
func (s *userService) GetUser(id int) string {
// 模拟耗时操作
return fmt.Sprintf("User-%d", id)
}
现在需要为 GetUser 方法增加日志记录能力,而不修改原始逻辑。我们可以创建一个日志装饰器:
type loggingDecorator struct {
service UserService
}
func NewLoggingDecorator(s UserService) UserService {
return &loggingDecorator{service: s}
}
func (d *loggingDecorator) GetUser(id int) string {
fmt.Printf("Calling GetUser with ID: %d\n", id)
result := d.service.GetUser(id)
fmt.Printf("GetUser returned: %s\n", result)
return result
}
使用时只需将原始服务包装起来:
完全公开源代码,并无任何许可限制 特别基于大型电子商务网站的系统开发 Microsoft SQL Server 2000后台数据库,充分应用了存储过程的巨大功效 基于类模块的扩展数据访问能力支持任何类型的大型数据库 加密用户登录信息(cookie) 易于安装的系统和应用功能 100%的asp.net的代码,没有COM,java或者其他的格式 完全基于MS建议的系统安全设计 最佳的应用程序,数据库
service := &userService{}
loggedService := NewLoggingDecorator(service)
loggedService.GetUser(42) // 自动输出日志
链式装饰:叠加多个功能
装饰者模式的强大之处在于可叠加多个装饰器。比如再加一个缓存装饰器:
type cacheDecorator struct {
service UserService
cache map[int]string
}
func NewCacheDecorator(s UserService) UserService {
return &cacheDecorator{
service: s,
cache: make(map[int]string),
}
}
func (c *cacheDecorator) GetUser(id int) string {
if name, ok := c.cache[id]; ok {
return name
}
name := c.service.GetUser(id)
c.cache[id] = name
return name
}
然后可以按顺序组合多个装饰器:
service := &userService{}
cached := NewCacheDecorator(service)
logged := NewLoggingDecorator(cached)
logged.GetUser(42) // 先走日志,再查缓存,最后调用真实服务
logged.GetUser(42) // 缓存生效,但仍会打印日志
执行顺序由包装顺序决定,外层装饰器先触发。
实际应用场景建议
装饰者模式特别适合以下场景:
- 中间件逻辑:如 API 请求的日志、认证、限流
- 性能监控:统计方法执行时间
- 事务管理:自动开启/提交数据库事务
- 错误处理:统一捕获并记录异常
设计时注意保持每个装饰器职责单一,避免把所有功能塞进一个大装饰器里。同时确保装饰器和被装饰者都实现同一接口,保证类型一致性。
基本上就这些。Go 的接口和组合机制让装饰者模式实现简洁自然,是扩展功能时值得掌握的技巧。









