Ланцюжок Обов’язків (Chain of responsibility), Паттерни в C# і

Ланцюжок Обов'язків (Chain of responsibility) - поведінковий шаблон проектування, який дозволяє уникнути жорсткої прив'язки відправника запиту до одержувача, дозволяючи об'єктам обробити запит. Всі можливі обробники запиту утворюють ланцюжок, а сам запит переміщається цим ланцюжком, поки один з її об'єктів не обробить запит. Кожен об'єкт при отриманні запиту вибирає або обробити запит або передати виконання запиту наступному по ланцюжку.

Коли застосовується ланцюжок обов'язків?

Коли є більше одного об'єкта, який може обробити певний запит

Коли треба передати запит на виконання одному з кількох об'єктів, точно не визначаючи, якому саме об'єкту

Коли набір об'єктів задається динамічно

responsibility

Формальне визначення мовою C#:

Handler: визначає інтерфейс для обробки запиту. Також може визначати посилання на наступний обробник запиту

ConcreteHandler1 та ConcreteHandler2: конкретні обробники, які реалізують функціонал для обробки запиту. При неможливості обробки та наявності посилання на наступний оброблювач, передають запит цьому оброблювачу

В даному випадку для простоти прикладу як параметр передається деяке число, і в залежності від значення даного числа обробники приймають рішення про обробку запиту.

Client : надсилає запит об'єкту Handler

Тобто у нас утворюється невеликий ланцюжок обробки запиту:

chain

Використання ланцюжка обов'язків дає нам такі переваги:

Ослаблення зв'язаності між об'єктами. Відправнику та одержувачу запиту нічого не відомо один про одного. Клієнту невідомий ланцюжок об'єктів, які саме об'єкти складають його, як запит у ньому.передається.

У ланцюжок можна додавати нові типи об'єктів, які реалізують спільний інтерфейс.

У той же час у патерна є недолік: ніхто не гарантує, що запит буде остаточно оброблений. Якщо необхідного оброблювача в ланцюжку не виявилося, запит просто виходить з ланцюжка і залишається необробленим.

Використання патерну часто зустрічається в нашому житті. Досить поширена ситуація, коли чиновники перекладають один на одного по ланцюжку виконання якоїсь справи, і воно, зрештою, виявляється не виконаним. Або коли ми йдемо до поліклініки, але при цьому точно не знаємо характеру захворювання. У цьому випадку ми йдемо до терапевта, а він, залежно від захворювання, вже може або сам лікувати, або відправити на лікування іншим спеціалізованим лікарям.

Розглянемо конкретний приклад. Припустимо, необхідно надіслати людині певну суму грошей. Однак ми точно не знаємо, який спосіб відправлення може використовуватися: банківський переказ, системи переказу типу WesternUnion та Unistream або система онлайн-платежів PayPal. Нам просто треба внести суму, вибрати людину та натиснути на кнопку. Подібна система може використовуватися на сайтах фрілансу, де всі відносини між виконавцями та замовниками відбуваються опосередковано через функції системи та де не треба знати точні дані одержувача.

Клас Receiver за допомогою конструктора і параметрів, що передаються в нього, встановлює можливі використовувані системи платежів. При здійсненні платежу кожен окремий об'єкт PaymentHandler перевірятиме установку в одержувача певного типу платежів. І якщо відбудеться зіставлення типу платежів у одержувача об'єкту PaymentHandler, цей об'єкт виконує платіж. Якщо ж необхідного способу платежів небуде визначено, що гроші залишаються в системі.

При цьому перевагою ланцюжка є і те, що вона дозволяє розташувати послідовність об'єктів-обробників у ній залежно від їхнього пріоритету.