Ответ
Chain of Responsibility — это поведенческий паттерн проектирования, который позволяет передавать запросы последовательно по цепочке обработчиков. Каждый обработчик решает, может ли он обработать запрос сам, или же он передает его следующему обработчику в цепочке.
Самый частый и идиоматичный пример использования этого паттерна в Go — это HTTP middleware.
Пример: Middleware для HTTP-сервера
Каждый middleware — это звено в цепочке. Он выполняет свою логику (например, логирование или аутентификацию) и передает управление следующему обработчику.
package main
import (
"fmt"
"log"
"net/http"
"time"
)
// Middleware для логирования запросов
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", r.Method, r.URL.Path)
// Передаем управление следующему обработчику в цепочке
next.ServeHTTP(w, r)
log.Printf("Completed in %v", time.Since(start))
})
}
// Middleware для проверки "аутентификации"
func AuthMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("X-API-KEY") != "secret" {
http.Error(w, "Forbidden", http.StatusForbidden)
return // Прерываем цепочку, если аутентификация не пройдена
}
// Передаем управление дальше
next.ServeHTTP(w, r)
})
}
// Конечный обработчик запроса
func finalHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, World!")
}
func main() {
final := http.HandlerFunc(finalHandler)
// Собираем цепочку: сначала логирование, потом аутентификация
chain := LoggingMiddleware(AuthMiddleware(final))
http.Handle("/", chain)
log.Fatal(http.ListenAndServe(":8080", nil))
}
Плюсы:
- Гибкость: Позволяет динамически добавлять, удалять и изменять порядок обработчиков.
- Разделение ответственности: Каждый обработчик сфокусирован на одной задаче (логирование, аутентификация, кэширование и т.д.).
- Слабая связность: Обработчик не знает о структуре цепочки или о других обработчиках, он знает только о следующем звене.
Минусы:
- Нет гарантии обработки: Запрос может пройти всю цепочку и остаться необработанным.
- Сложность отладки: Может быть трудно отследить, какой именно обработчик в цепочке вызвал ошибку или повел себя некорректно.