Ответ
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))
}
Плюсы:
- Гибкость: Позволяет динамически добавлять, удалять и изменять порядок обработчиков.
- Разделение ответственности: Каждый обработчик сфокусирован на одной задаче (логирование, аутентификация, кэширование и т.д.).
- Слабая связность: Обработчик не знает о структуре цепочки или о других обработчиках, он знает только о следующем звене.
Минусы:
- Нет гарантии обработки: Запрос может пройти всю цепочку и остаться необработанным.
- Сложность отладки: Может быть трудно отследить, какой именно обработчик в цепочке вызвал ошибку или повел себя некорректно.
Ответ 18+ 🔞
А, паттерн Chain of Responsibility! Ну это ж как в жизни, блядь: приходишь ты в какую-нибудь контору, а там тебя по кабинетам гоняют — один говорит "не моё", второй "не ко мне", третий "а вы справку взяли?", и в итоге ты с пустыми руками, сука, выходишь, и все довольны, кроме тебя, пиздец.
Вот смотри, в программировании это выглядит примерно так же, только полезнее. Берёшь ты запрос и запускаешь его по цепочке обработчиков, как горячую картошку. Каждый мудак в цепочке смотрит — его ли это проблема или нет. Если его — обрабатывает, если нет — кидает следующему. Проще говоря, это как очередь в поликлинике, только без бабулек.
Самый, блядь, классический пример — это HTTP middleware в Go. Прям идиоматичная хуйня, все так делают.
Пример: 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))
}
Плюсы, ёпта:
- Гибкость: Хочешь — добавь нового мудака в цепочку, хочешь — выкини. Порядок менять — раз плюнуть.
- Разделение ответственности: Один логирует, другой проверяет, третий кеширует. Каждый сидит в своей параше и не лезет в чужую, красота.
- Слабая связность: Каждый обработчик знает только про следующего идиота в цепочке, а не про всю систему. Это как в тюрьме — знаешь только своего "соседа".
Минусы, блядь:
- Нет гарантии обработки: Запрос может прошататься по всей цепочке, как последний лох, и так нигде и не зацепиться. Прошёл всех — и свободен, пиздец.
- Сложность отладки: Попробуй найди, кто именно из этих уродов в цепочке всё сломал. Это как искать иголку в стоге сена, если в каждом стоге сидит по программисту.