Chain of Responsibility : Design Pattern

Oct 30, 2022 By Puneet verma

Suppose we have a problem requiring several steps to reach the solution. Yeah, it's straightforward, make the methods for all the steps and call them from some base method.

feature1();
feature2();
feature3();


Above hardcoding may be a problem in some scenarios like

  • If the sequence is also not known
  • The sequence may be different

Chain of responsibility comes handly for such a situations

Chain of Responsibility 

  • It is a behavioural design pattern that lets you pass requests along a chain of handlers. 
  • Upon receiving a request, each handler processes it or passes it to the next handler in the chain. 
  • A client doesn't know which part of the chain will be processing the request and will send the request to the first object in the chain.
  • Each object in the chain has its implementation to process the request, either full or partial, or send it to the next object in the chain.
  • Order of the chain may or may not be important, depending on the business requirements.
  • It is the object-oriented version of if …elseif… elseif … else and makes us capable of rearranging the condition-action blocks dynamically at the run-time

chain of responsibility

Let's take a few examples to understand it.

Example 1

An employee needs approval for a task. He asked his manager for approval. But as it requires monetary approval, he passes the request to a higher authority handling financials.

Example 2

Your laptop not working. You called customer care and recorded a voice asking to press 1-9 based on your requirement. Once you select any option call will be transferred to some human. He will understand your issue and will redirect you to the engineer. 

Usages

  • We can have multiple catch blocks in a try-catch block code. Each catch block process only a particular type of exception  

    When any exception occurs in the try block, it is sent to the first catch block to process. If the catch block cannot process it, it forwards the request to the next object in the chain, i.e. next catch block. The exception is thrown outside the calling program if even the last catch block cannot process it.

  • Middleware in laravel

  • ATM Dispense machine

  • Input/form validation You could chain together things such as validating min/max length, correct characters (a-z0-9 alphanumeric), valid URL, etc).

<?php

interface Handler
{
    public function setNext(Handler $handle);
    public function handle($request);
}

class  AbstractHandler implements Handler
{
    private $nextHandler;
    public function setNext(Handler $handler)
    {
        $this->nextHandler = $handler;
        return $handler;
    }
    public function handle($request)
    {
        if ($this->nextHandler) {
            return $this->nextHandler->handle($request);
        }

        return null;
    }
}

class MonkeyHandler extends AbstractHandler
{
    public function handle($request)
    {
        if ($request === "Banana") {
            return "Monkey: I'll eat the " . $request . ".\n";
        } else {
            return parent::handle($request);
        }
    }
}

class SquirrelHandler extends AbstractHandler
{
    public function handle($request)
    {
        if ($request === "Nut") {
            return "Squirrel: I'll eat the " . $request . ".\n";
        } else {
            return parent::handle($request);
        }
    }
}
class DogHandler extends AbstractHandler
{
    public function handle($request)
    {
        if ($request === "MeatBall") {
            return "Dog: I'll eat the " . $request . ".\n";
        } else {
            return parent::handle($request);
        }
    }
}


$monkey   = new MonkeyHandler();
$squirrel = new SquirrelHandler();
$dog      = new DogHandler();

$monkey->setNext($squirrel)->setNext($dog);

$food = 'Nut';
$result = $monkey->handle($food);
echo $result? $result:$food . " was left untouched \n";


$food = 'Banana';
$result = $monkey->handle($food);
echo $result? $result:$food . " was left untouched \n";

$food = 'Chips';
$result = $monkey->handle($food);
echo $result? $result:$food . " was left untouched \n";

$food = 'Banana';
$result = $squirrel->handle($food);
echo $result? $result:$food . " was left untouched \n";

Output

Squirrel: I'll eat the Nut.
Monkey: I'll eat the Banana.
Chips was left untouched
Banana was left untouched