Коротке пояснення:
Ланцюжок обов’язків (CoR, Chain of Command, Chain of Responsibility) — це поведінковий патерн проектування, що дає змогу передавати запити послідовно ланцюжком обробників. Кожен наступний обробник вирішує, чи може він обробити запит сам і чи варто передавати запит далі ланцюжком.
Плюси та мінуси:
Плюси:
- Зменшує залежність між клієнтом та обробниками.
- Реалізує принцип єдиного обов’язку (
S
OLID - Single responsibility). - Реалізує принцип відкритості/закритості (S
O
LID - Open/Close principle).
Мінуси:
- Запит може залишитися ніким не опрацьованим.
Приклад коду:
class Handler
attr_accessor :successor
def initialize(successor = nil)
@successor = successor
end
def handle_request(request)
if can_handle?(request)
handle(request)
elsif successor
successor.handle_request(request)
else
puts "Request #{request} was left unhandled."
end
end
private
def can_handle?(request)
raise NotImplementedError, 'You must implement the can_handle? method'
end
def handle(request)
raise NotImplementedError, 'You must implement the handle method'
end
end
class ConcreteHandlerA < Handler
private
def can_handle?(request)
request == :help
end
def handle(request)
puts "ConcreteHandlerA handled request #{request}"
end
end
class ConcreteHandlerB < Handler
private
def can_handle?(request)
request == :process
end
def handle(request)
puts "ConcreteHandlerB handled request #{request}"
end
end
# Клієнтський код
handler1 = ConcreteHandlerA.new
handler2 = ConcreteHandlerB.new(handler1)
handler2.handle_request(:process) # Буде оброблено ConcreteHandlerB
handler2.handle_request(:help) # Буде передано до ConcreteHandlerA
handler2.handle_request(:unknown) # Не буде оброблено
У цьому прикладі створено базовий клас Handler, який визначає інтерфейс для обробки запитів та містить посилання на наступний обробник у ланцюгу (successor). Класи ConcreteHandlerA
та ConcreteHandlerB
реалізують логіку обробки для конкретних типів запитів. Якщо об'єкт не може обробити запит, він передає запит наступному обробнику у ланцюзі. Якщо жоден обробник не може опрацювати запит, то запит залишається ніким не опрацьованим.
Аналогія у житті: У ресторані ви робите специфічний запит офіціанту, який передає його від кухаря до помічника, поки не знайдеться той, хто може задовольнити ваші смакові уподобання, подібно до того, як у патерні "Ланцюжок обов'язків" запит передається від одного обробника до іншого, поки не буде знайдено рішення.
Аналогія у Ruby on Rails:
Middleware
в Rails — це серія компонентів, які обробляють вхідні HTTP-запити по ланцюгу, де кожен компонент виконує певну роль, перш ніж передати запит наступному обробнику.
Реалізація в сторонніх бібліотеках:
Organizers for Interactor gem.