Ланцюжок відповідальності

Аналогія

Допустимо, для вашого банківського рахунку є три способи оплати (A, B і C). Кожен має на увазі різні доступні суми грошей: A – 100 доларів, B – 300, C – 1000. Пріоритетність способів при оплаті: А, потім В, потім С. Ви намагаєтеся купити щось за 210 доларів. На підставі «ланцюжка відповідальності» система спробує оплатити способом А. Якщо грошей вистачає, то оплата проходить, а ланцюжок переривається. Якщо грошей не вистачає – то система переходить до способу, і т.д.

Стисло

Шаблон «Ланцюжок відповідальності» дозволяє створювати ланцюжки об’єктів. Запит входить з одного кінця ланцюжка і рухається від об’єкта до об’єкта, доки не буде знайдено відповідний обробник.

Вікіпедія

Шаблон «Ланцюжок відповідальності» містить вихідний керуючий об’єкт та ряд обробних об’єктів. Кожен обробний об’єкт містить логіку, визначальну типи командних об’єктів, які може обробляти, інші передаються по ланцюжку наступному обробному об’єкту.

Приклад

Створимо основний банківський рахунок, що містить логіку зв’язування рахунків у ланцюжка, і самі рахунки.

abstract class Account
{
    protected $successor;
    protected $balance;

    public function setNext(Account $account)
    {
        $this->successor = $account;
    }

    public function pay(float $amountToPay)
    {
        if ($this->canPay($amountToPay)) {
            echo sprintf('Paid %s using %s' . PHP_EOL, $amountToPay, get_called_class());
        } elseif ($this->successor) {
            echo sprintf('Cannot pay using %s. Proceeding ..' . PHP_EOL, get_called_class());
            $this->successor->pay($amountToPay);
        } else {
            throw new Exception('None of the accounts have enough balance');
        }
    }

    public function canPay($amount): bool
    {
        return $this->balance >= $amount;
    }
}

class Bank extends Account
{
    protected $balance;

    public function __construct(float $balance)
    {
        $this->balance = $balance;
    }
}

class Paypal extends Account
{
    protected $balance;

    public function __construct(float $balance)
    {
        $this->balance = $balance;
    }
}

class Bitcoin extends Account
{
    protected $balance;

    public function __construct(float $balance)
    {
        $this->balance = $balance;
    }
}

Тепер за допомогою певних лінків (Bank, Paypal, Bitcoin) підготуємо ланцюжок:

// Зробимо такий ланцюжок
// $bank->$paypal->$bitcoin
//
// Пріоритет у банку
// Якщо банк не може сплатити, переходимо до Paypal
// Якщо Paypal не може, переходимо до Bitcoin

$ Bank = New Bank (100); // У банку баланс 100
$ Paypal = New Paypal (200); // У Paypal баланс 200
$bitcoin = новий Bitcoin(300); // У Bitcoin баланс 300

$bank->setNext($paypal);
$paypal->setNext($bitcoin);

// Почнемо з банку
$ bank->pay (259);

// Вихідний вигляд
// ==============
// Не можна сплатити за допомогою банку. Обробляю...
// Не можна сплатити за допомогою Paypal. Обробляю...
// Сплачено 259 за допомогою Bitcoin!

Залишити коментар