PHP Chain of Responsibility : Making a Selection

The Chain of Responsibility (CoR) design pattern is used when you need a request handled by the most appropriate object for the request. You don’t need to worry about which object handles the request or even if they’ll handle it the same all the time. For example, suppose you have a constantly changing marketplace and the specs of your request change as well. Rather than building an application that links a specific request to a specific request handler the CoR pattern decouples the two so that when a request is sent, all you know is that the most appropriate object will handle it. Our department buys USB drives in bulk from China. In the request for the drives I put in a set of criteria and send the request to my Chinese buyer. He is instructed to get the lowest price for the drives as long as they meet the specs in the required bulk. Now I don’t know which manufacturer will win the contract (which object will handle the request), but since I trust my agent in China, I am confident he’ll get the best price even though the price will vary depending on everything from the dollar’s exchange rate with China to the availability of USB drives. Because so many variables change, I need the flexibility that changes with both the request and the request handler. That’s something like the way the CoR design pattern works—it takes a request and finds the most appropriate way to handle it.

Play the application to see what happens (not much) and download the code using the following buttons:

Chain of Responsibility Overview

Because looking at a Class Diagram is useful for seeing the larger context of the design pattern, we’ll look at it first and then go about describing its features.

Figure 1: Chain of Responsibility Class Diagram

This looks fairly simple, and at the basic level it really is. Like some of the other design patterns, the Client is part of the pattern, and so it’s integral. At the center of the pattern is the Handler interface. For the time being, think of the interface as an abstract class because that is what is used in the initial example. The abstract class includes a function for setting successors in a chain and another to handle a request. Finally, the ConcreteHandler classes represent the specific and different classes that handle requests. Generally speaking, an application would include several ConcreteHandler classes, and each is set up in a chain to deal with requests where appropriate.

Unchain My Request

In their work, the Gang of Four, illustrate the CoR using a Help desk. The Help desk is set up in a hierarchy with different Help topics. As a request moves through the hierarchy it attempts to find the concrete handler that deals with its query. Another good example (my favorite) is provided by the Freemans in their Head First Design Patterns book. Their example envisions a company that gets different kinds of email, and to sort it out, the CoR design pattern is used. It has separate handlers (ConcreteHandler) for fan mail, spam, complains and so forth. So, when an email arrives, it is automatically handled in the appropriate manner moving it along a chain. Both of these examples share the concept of uncoupling the request from the handler. In this way, both requests and handlers can be changed without disrupting the larger program. As anyone who has worked with a program to handle products or services in a rapidly changing environment knows, your design needs this kind of flexibility.

Figure 2 provides a general idea of a chain of concrete handlers set up in succession. When the request comes in, it is examined by ConcreteHandler A. If A cannot handle the request, it is passed on to ConcreteHandle B and so forth until it either runs out of concrete handlers or is handled. The different colored diamonds represent the different ways of handling a request. The process terminates once the request is handled.


Figure 2: Request Chain

If you want some kind of handler to deal with unhandled requests, the last concrete handler in the chain (ConcreteHandler E in Figure 2) could be a residual one that issues a notice informing the user that the request could not be handled. However, the alternative of simply not handling a request because the criteria for handling is not in the chain of concrete handlers is perfectly acceptale.

The Implicit Receiver

One of the two key concepts in the CoR pattern is implicit receiver. Even though the requesting object may not have any idea of which concrete handler will handle a request, the one that actually handles it is the implicit receiver. That clears up a lot of possible confusion. Given the criteria of the request, only one of the concrete handlers can meet that criteria, and so implicitly that is the receiver. It’s a simple concept but one that you need to keep in mind.

Because the request is uncoupled from the receiver, you can easily add more concrete classes to be the implicit receiver. Imagine a business with a CoR that finds items in certain price ranges. Let’s say that a merchant finds that most people will spend $50 on a project. He has handlers for under $50 and from $50 to $100. Research shows that most of the under $50 sales are actually for around $20. To increase revenue, he adds a new concrete handler that offers a $35 to $65 range. Because he used a CoR design pattern, all he needs to do is to add a handler for that range and make minor adjustments to the concrete handlers below and above that range. Because the receivers are implicit and uncoupled from the request, such adjustments are easy and the program can be changed without having to refactor the entire application.

The Successor

The second key concept in the CoR is successor. To move a request along a chain and to keep the receiver implicit, each object must maintain a common interface. The successor defines a way to move along the chain of objects and shares the same interface as do the receiver objects (concrete classes). As a result, the pattern requires some method for specifying successors in the interface but must hold the interface. In the class diagram in Figure 2, you can see the successor in the Handler interface looping back to itself.

One way of setting up this method can be seen in the interface itself. A successor object is typed as the interface (Handler). Then the method parametizes the successor object. The following snippet shows how this looks:

...
        abstract public function handleRequest($request); 
        abstract public function setSuccessor($nextService);                
...

Each of the concrete handlers includes a way to pass on the request to the next concrete handler using the successor object .

A Simple PHP Chain of Command Application

In coming up with an application, I envisioned a request-for-information page where the user could select from one of three radio buttons. Depending on the selection, the Chain of Responsibility would send the request to be handled by the appropriate concrete handler. (It “handles” it by sending a message to the screen, but it could do anything you want.)

The client sends out a request with request implied by the selection of the radio button. It begins with a query for “Information” and works up the chain until he finds a match to the originating query. It’s a simple application, but one where you can see all of the parts working together. The application has the following components:

  • Handler class that acts as an interface for the application
  • Three concrete handler classes that act as receivers
  • A Client class that makes the request
  • A request that calls the Client

Handler Class

This first class acts as an interface. It is an abstract class and for the purposes of design patterns, abstract classes and interfaces are often referred to a interfaces. In the Gang of Four’s book, a reference to an interface generally means any class from which concrete classes derive with the emphasis on the set of methods held in the interface whether it is a PHP interface structure or an abstract class.


 
        abstract class Handler
        {
                abstract public function handleRequest($request); 
                abstract public function setSuccessor($nextService);                
        }
 
?>

As you can see, the Handler class has two methods. The first method will be used to set the successor and the second method to handle requests. However, because the request handler involves different requirements for each concrete handler, the method remains abstract in the Handler class.

Concrete Handler Classes

Because the Handler class is an abstract one, all of the subclasses provide concrete methods in the Handler class. The HandleRequest( ) method needs to communicate the limits of its ability to handle the request and pass on to its successor if it cannot handle it. The following three concrete handlers do that:

//Information.php

class Information extends Handler
{
    private $successor;
 
    public function setSuccessor($nextService)
    {
        $this->successor=$nextService;
    }
 
    public function handleRequest ($request)
    {
        if ($request->getService() == "Information Design")
        {
            echo ("All types of information can be easily stored  " . "
"
. "and retrieved in a MySQL database controlled by PHP."); } else if ($this->successor != NULL) { $this->successor->handleRequest ($request); } } } ?>   //Services.php class Services extends Handler { private $successor;   public function setSuccessor($nextService) { $this->successor=$nextService; }   public function handleRequest($request) { if ($request->getService() == "MySQL Database Design") { echo "Design both regular and relational databases" . "
"
; } else if ($this->successor != NULL) { $this->successor->handleRequest($request); } } } ?>   //Software.php class Software extends Handler { private $successor;   public function setSuccessor($nextService) { $this->successor=$nextService; }   public function handleRequest ($request) { if ($request->getService() == "Software Security") { echo ("We can provide client- and server- based validation with password security"); } else if ($this->successor != NULL) { $this->successor->handleRequest ($request); } } } ?>

The concrete handlers evaluate the weight of the request. The chain of responsibility begins with the Information class. If it cannot handle the request, it passes it on to its successor, the Services class. If the Services class cannot handle it, it is passed on to the Product class which will handle it. In this particular example, we will be using radio buttons to make the request, and so we can be assured that if a request is made (a radio button is selected), it will be handled. In some cases a Chain of Responsibility may be given a request that cannot be handled. In such cases, the developer has the choice of sending the user a message indicating that the request cannot be handled or do nothing.

Request and Client Classes

The Client class implements the request and establishes the hierarchy in the chain of responsibility. The Request class is simply a way of encapsulating the request, which is nothing more than getter/setter methods. The getter and setter methods are set up and the value for a load is paramaritized in the main method.

//Request.php

class Request
{
    private $value;
 
    public function __construct($service)
    {
        $this->value=$service;
    }
 
    public function getService()
    {
        return $this->value;
    }
}
?>

You will notice that all of the concrete handlers hold a reference to the Request class. In effect it is a mixin class used by both the Client class and ConcreteHandler classes. However, it is only instantiated by the Client class. As noted, though, it encapsulates the request following good OOP practices.

//Client.as

class Client
{
    public function __construct($queryNow)
    {
        $Info = new Information();
        $CodeSer = new Services();
        $Product = new Software();
        $Info->setSuccessor($CodeSer);
        $CodeSer->setSuccessor($Product);
 
        // Generate and process load requests
        $loadup = new Request($queryNow);
        $Info->handleRequest ($loadup);
    }
}
?>

In looking at the Client class, all of the request objects are instantiated and then the successors are set. Three different request values should test each of the three concrete classes’ ability to recognize itself as the implicit receiver. The Client begins each request with the object that is at the beginning of the chain of responsibility.

Finally, you will need a set of operations to launch the Client. Here’s what we used:

//TestCoR.php

ini_set("display_errors","2");
ERROR_REPORTING(E_ALL);
include_once('Client.php');
include_once('Handler.php');
include_once('Request.php');
include_once('Services.php');
include_once('Software.php');
include_once('Information.php');
if (isset($_POST['sendNow']))
{
    $queryNow  = $_POST['query'];
}
$makeRequest = new Client($queryNow);
?>

Many PHP programs use far fewer files for such small project as we use here. However, the separate files for classes and interfaces promotes the idea loose coupling. It makes it easy to change because you know that no more than a single class is in each file. When it comes time to change, you can switch out the parts like boxcars on a train. Each is an encapsulated operation that has a single responsibility. Some you will re-use, others will be changed and still others will be removed. All this can be done without the program crashing.

A standard HTML program provides the UI for the user to make a request.

DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        
        <style type="text/css">
            body
            {
                background-color:#FFCC33;
                color:#0e6829;
                font-family:Verdana, Arial, Helvetica, sans-serif;
                font-size:10px;
            }
        style>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
        <title>Customer Querytitle>
    head>
    <body>
        <img src="logo/LogoMoon.png" />
        <form action="TestCoR.php" method="post">
                Select the service that will help you or your company.<br/>
            <p/>
            <input type="radio" name="query" value="Software Security" />
            &nbsp; Software Security<br/>
            <input type="radio" name="query" value="MySQL Database Design" />
            &nbsp; MySQL Database Design<br/>
            <input type="radio" name="query" value="Information Design" />
            &nbsp; Information Design<br/>
            <p/>
            <input type="submit" name="sendNow" value="Click here to send information to Sandlight" />
        form>
        <p/> *Sandlight shares this information with no one.<br/>
                We're as paranoid as you are.
    

Figure 3 shows the selection UI:

Figure 3: User request form

The button-click event calls the TestCoR.php file to launch the operations that fire the Client class.

When you test the program, you will get one of the following three messages:

  1. We can provide client- and server- based validation with password security
  2. Design both regular and relational databases
  3. All types of information can be easily stored and retrieved in a MySQL database controlled by PHP.

Each of the three requests was handled by the appropriate concrete handler. Even better, if new kinds of requirements or requests are brought in, the changes are only in the concrete handlers.

Reader Uses and Feedback

The example is a simple one, and given the task, you may be thinking that you could have handled it just as well with a single class. You’d be right. However, because a primary use of PHP is to

Copyright © 2010 William Sanders. All Rights Reserved.

2 Responses to “PHP Chain of Responsibility : Making a Selection”


  • This pattern could be an alternative to use many if /else / else if, with classes in cleaner way.

    Excellent article.

  • Hi Nbari,

    Sorry it took me so long to reply to you. I was right in the middle of my new book, Learning PHP Design Patterns when I got your comment. (See link). I am now writing a new Chain of Responsibility (CoR) post for this blog that can be used as a “device sniffer.” As more and more devices come into being, we’ll need a flexible sniffer to easily add each new device user agent code. I thought that a CoR pattern would do the trick, and like you said, it’s a lot more efficient than adding more conditional statements. The Client, though, is another story!

    Kindest regards,
    Bill

Leave a Reply