Цепочка обязанностей (Chain of Responsibility)
Другое название
Назначение
Некий запрос должен быть обработан в цепочке взаимосвязанных объектов (список, дерево - движение от листьев к корню). Объект либо обрабатывает запрос, либо передвает по цепочке следующему объекту. Если ни один из объектов не обработал запрос, то может происходить какое-то действие.
Описание
Имеется цепочка объектов, каждый хранит ссылку на следующий объект (как правило, объект более верхнего уровня) Запрос перемещается по цепочке объектов вверх пока один из них не обработает этот запрос. У объекта, отправившего запрос на обработку, отсутствует информация о том, какой объект в цепочке обработает запрос.
Пример: докладная пишется непосредственному начальнику, он либо реагирует на нее, либо передает по иерархии вверх своему непосредственному начальнику и т.д.
Использование
Паттерн Цепочка обязанностей используется если есть более одного объекта, способного обработать запрос, причем, настоящий обработчик неизвестен и должен быть найден автоматически
Реализация
Диаграмма классов
Участники
Пример
class MainApp
{
static void Main()
{
// Setup Chain of Responsibility
Handler h1 = new ConcreteHandler1();
Handler h2 = new ConcreteHandler2();
Handler h3 = new ConcreteHandler3();
h1.SetSuccessor(h2);
h2.SetSuccessor(h3);
// Generate and process request
int[] requests = { 2, 5, 14, 22, 18, 3, 27, 20 };
h1.HandleRequest(2);
h1.HandleRequest(22);
h1.HandleRequest(222);
}
}
abstract class Handler
{
protected Handler successor;
public void SetSuccessor(Handler successor)
{
this.successor = successor;
}
public abstract void HandleRequest(int request);
}
class ConcreteHandler1 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 0 && request < 10)
{
Console.WriteLine("{0} handled request {1}", this.GetType().Name, request);
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}
class ConcreteHandler2 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 10 && request < 20)
{
Console.WriteLine("{0} handled request {1}", this.GetType().Name, request);
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}
class ConcreteHandler3 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 20 && request < 30)
{
Console.WriteLine("{0} handled request {1}",this.GetType().Name, request);
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}
Достоинства и недостатки
- Паттерн Цепочка обязанностей освобождает объект от ответственности знать, кто обработает его запрос
- Объекты, обрабатывающие запрос, можно включать в цепочку динамически
- Недостаток: нет гарантий, что запрос вообще будет обработан