Go 的每一个框架都在用的设计模式——装饰器模式
Go 的每一个框架都在用的设计模式——装饰器模式不修改一行源码,如何让函数"无限增强"?揭秘 Go 框架背后的核心设计模式一、从一个真实问题开始假设你正在开发一个 HTTP 服务,需要给核心业务函数添加以下功能:// 核心业务函数 func HandleRequest(w http.ResponseWriter, r *http.Request) { // 处理请求... w.Write([]byte("Hello, World!")) }需求来了:添加日志记录(记录每个请求的 URL、耗时)添加认证检查(验证 Token)添加限流保护(防止恶意请求)添加 panic 恢复(防止服务崩溃)添加指标监控(Prometheus metrics)** naive 的做法:**func HandleRequest(w http.ResponseWriter, r *http.Request) { // 1. 日志 start := time.Now() log.Printf("Request: %s", r.URL) defer log.Printf("Duration: %v", time.Since(start)) // 2. 认证 token := r.Header.Get("Authorization") if !validateToken(token) { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } // 3. 限流 if !limiter.Allow() { http.Error(w, "Too Many Requests", http.StatusTooManyRequests) return } // 4. Panic 恢复 defer func() { if err := recover(); err != nil { log.Printf("Panic recovered: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) } }() // 5. 指标监控 metrics.RequestCounter.Inc() // 6. 核心业务逻辑(终于看到了!) w.Write([]byte("Hello, World!")) }问题:❌ 核心业务逻辑被"横切关注点"淹没❌ 代码难以测试(每个功能耦合在一起)❌ 想给其他 handler 添加相同功能?复制粘贴!❌ 修改任何一个功能都可能影响其他功能有没有一种方式,能不修改原函数,动态添加这些功能?答案是:装饰器模式(Decorator Pattern)二、装饰器模式核心思想2.1 什么是装饰器模式?装饰器模式:动态地给对象添加新的功能,而不改变其原有结构。用 Go 的话说:用一个函数包装另一个函数,在调用前后添加额外逻辑。2.2 核心结构┌─────────────────────────────────────────┐ │ 原始函数 (Handler) │ │ func(w, r) { 业务逻辑 } │ └─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────┐ │ 装饰器 1 (LoggingDecorator) │ │ func(w, r) { 日志; 调用原始函数 } │ └─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────┐ │ 装饰器 2 (AuthDecorator) │ │ func(w, r) { 认证; 调用装饰器 1 } │ └─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────┐ │ 装饰器 3 (RateLimitDecorator) │ │ func(w, r) { 限流; 调用装饰器 2 } │ └─────────────────────────────────────────┘关键:装饰器本身和被装饰的对象遵循相同的接口!三、Go 中的装饰器模式实现3.1 HTTP Handler 装饰器// 1. 日志装饰器 func LoggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() // 调用前:记录请求 log.Printf( "Started %s %s from %s", r.Method, r.URL.Path, r.RemoteAddr, ) // 调用原始 handler next.ServeHTTP(w, r) // 调用后:记录耗时 log.Printf( "Completed %s %s in %v", r.Method, r.URL.Path, time.Since(start), ) }) } // 2. 认证装饰器 func AuthMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("Authorization") if token == "" { http.Error(w, "Missing authorization token", http.StatusUnauthorized) return } if !validateToken(token) { http.Error(w, "Invalid authorization token", http.StatusUnauthorized) return } // 认证通过,调用下一个 handler next.ServeHTTP(w, r) }) } // 3. 限流装饰器 func RateLimitMiddleware(limiter *rate.Limiter) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if !limiter.Allow() { http.Error(w, "Rate limit exceeded", http.StatusTooManyRequests) return } next.ServeHTTP(w, r) }) } // 4. Panic 恢复装饰器 func RecoveryMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer func() { if err := recover(); err != nil { log.Printf("Panic recovered: %v", err) debug.PrintStack() http.Error(w, "Internal Server Error", http.StatusInternalServerError) } }() next.ServeHTTP(w, r) }) } // 5. 指标监控装饰器 func MetricsMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // 包装 ResponseWriter 以捕获状态码 rw := responseWriter{ResponseWriter: w, statusCode: http.StatusOK} start := time.Now() next.ServeHTTP(rw, r) duration := time.Since(start) // 记录指标 metrics.RequestCounter.WithLabelValues(r.URL.Path, rw.statusCode).Inc() metrics.RequestDuration.WithLabelValues(r.URL.Path).Observe(duration.Seconds(
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2435115.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!