1. Что такое паттерн Цепочка обязанностей
Паттерн Цепочка обязанностей - это поведенческий паттерн проектирования, который разрывает связь между отправителем и получателем запроса, позволяя нескольким объектам обрабатывать запрос. Каждый получатель содержит ссылку на другого получателя, и если не может обработать запрос, передает его следующему получателю, пока запрос не будет обработан или не достигнет конца цепочки.
2. Характеристики и преимущества паттерна Цепочка обязанностей
Характеристики и преимущества паттерна Цепочка обязанностей следующие:
- Разрывание связи между отправителем и получателем: Отправитель не должен заботиться о том, какой получатель обрабатывает запрос, ни о конкретных обработчиках в цепочке.
- Гибкость: Позволяет динамически добавлять, удалять или изменять порядок обработчиков в цепочке без модификации кода отправителя и получателя.
- Расширяемость: Легко расширять цепочку обязанностей, добавляя новые конкретные обработчики.
- Принцип единственной обязанности: Каждый конкретный обработчик должен заботиться только о своей собственной логике обработки.
- Настраиваемость: Цепь обработчиков может быть настроена в соответствии с потребностями, позволяя различным запросам иметь разные цепочки обработчиков.
3. Примеры практического применения паттерна Цепочка обязанностей
Паттерн Цепочка обязанностей имеет множество практических применений, таких как:
- Обработка запросов в веб-приложениях: Может использоваться для обработки различных типов запросов, таких как аутентификация идентичности, ведение журнала и проверка разрешений.
- Обработка ошибок: Может использоваться для обработки ошибок, при этом каждый обработчик отвечает за обработку определенного типа ошибок и пересылает ошибку следующему обработчику при необходимости.
- Обработка событий: Может использоваться для обработки различных типов событий, таких как события нажатия пользователем, сетевые запросы и так далее.
4. Реализация паттерна Цепочка обязанностей на Golang
4.1 UML-диаграмма классов
4.2 Введение в пример
На UML-диаграмме выше мы определили абстрактный обработчик (Handler) и два конкретных обработчика (ConcreteHandler1 и ConcreteHandler2). Клиент (Client) инициирует запросы, вызывая метод handleRequest обработчика.
4.3 Шаг 1 реализации: Определение интерфейса абстрактного обработчика
type Handler interface {
HandleRequest(request Request) error
SetNext(handler Handler)
}
type Request interface {
Condition bool
}
Интерфейс абстрактного обработчика определяет метод HandleRequest для обработки запросов и метод SetNext для установки следующего обработчика.
4.4 Шаг 2 реализации: Реализация конкретных классов обработчиков
type ConcreteHandler1 struct {
next Handler
}
func (h *ConcreteHandler1) HandleRequest(request Request) error {
// Логика обработки запроса
if request.Condition {
// Код обработки запроса
return nil
} else {
if h.next != nil {
return h.next.HandleRequest(request)
}
return errors.New("Получатель не найден")
}
}
func (h *ConcreteHandler1) SetNext(handler Handler) {
h.next = handler
}
type ConcreteHandler2 struct {
next Handler
}
func (h *ConcreteHandler2) HandleRequest(request Request) error {
// Логика обработки запроса
if request.Condition {
// Код обработки запроса
return nil
} else {
if h.next != nil {
return h.next.HandleRequest(request)
}
return errors.New("Получатель не найден")
}
}
func (h *ConcreteHandler2) SetNext(handler Handler) {
h.next = handler
}
Конкретные классы обработчиков реализуют интерфейс абстрактного обработчика и переопределяют методы HandleRequest и SetNext.
4.5 Шаг 3 реализации: Построение цепочки обязанностей
handler1 := &ConcreteHandler1{}
handler2 := &ConcreteHandler2{}
handler1.SetNext(handler2)
Путем создания экземпляров конкретных обработчиков и установки следующего обработчика строится цепочка обязанностей.
4.6 Шаг 4 реализации: Код клиента
func main() {
handler := &ConcreteHandler1{}
// Построение цепочки обязанностей
handler.SetNext(&ConcreteHandler2{})
// Отправка запроса
handler.HandleRequest(Request{Condition: true})
}
В коде клиента создается экземпляр конкретного обработчика, устанавливается следующий обработчик, и затем вызывается метод HandleRequest для отправки запроса.