Sunday, February 21, 2016

The Chain of Responsibility design pattern

It has been some time since my last post. Life get's busy I guess! So to pick things up a bit, I will add another design pattern in the series of tutorials (see previous posts such as Facade or Adapter and more).

The chain of responsibility design pattern is of the behavioral family and implements an approach where a sender/originator of a request can be served by any in a number of receiver objects. Each receiver object contains a reference to other receiver objects and the sender’s request is passed from receiver to receiver, till the request is served or all the receivers in the chain are traversed.

The main motivation of the pattern is to detach the request from a specific receiver. The use of the chain pattern allows to be decided at runtime, which object will serve a request, from a set of object that are able to do so. In the chain of responsibility pattern, it is possible that the request will not be served.

To showcase the pattern, lets consider a customer support center where clients can be served by English or Dutch speaking employees. Also, as probably you would have guessed, an employee that is already busy with a client, cannot serve another support request.

The followin UML class diagram provides an overview of the components of the tutorial:





















We start with an abstract class, named CustommerSupportEmployee. Usually an interface is used for the chain pattern and in general interfaces are preferable than extending a class (because you can only extend one) but I want to use a method across all receivers of our example. The source code, is shown below:
package com.tasosmartidis.design_patterns_tutorial.chain;

public abstract class CustomerSupportEmployee {
    private CustomerSupportEmployee nextInChain;
    private boolean employeeBusy = false;
    
    public abstract void serveCustomer(CustomerServiceRequest csRequest);
    
    void passRequestToNextInChain(CustomerServiceRequest csRequest, String noNextEmployeeMessage){
        if(nextInChain!=null)
            nextInChain.serveCustomer(csRequest);
        else
            System.out.println(noNextEmployeeMessage);
    }
        
    public void setNextInChain(CustomerSupportEmployee nextInChain){
        this.nextInChain = nextInChain;
    }

    public boolean isEmployeeBusy() {
        return employeeBusy;
    }

    public void setEmployeeBusy(boolean employeeBusy) {
        this.employeeBusy = employeeBusy;
    }   
}

The serveCustomer is the importnt one for the receiver objects. We use a boolean for checking if a customer support employee is busy which will help us with the workflow when showing the pattern. Simply put, if an employee (receiver) is busy, then passes the request to the next in chain. And passing to the next in chain is a helper method for doing that.

Next, we create two classes, a Dutch and an English customer support employee. Objects of these classes will be used as receivers of requests in the chain pattern demo. The code for these classes looks something like this:

package com.tasosmartidis.design_patterns_tutorial.chain;

public class CustomerSupportDutch extends CustomerSupportEmployee{
    private String name;
    
    public CustomerSupportDutch(String name) {
        this.name = name;
    }

    public void serveCustomer(CustomerServiceRequest csRequest) {
        if(!this.isEmployeeBusy()) {
            
            if(csRequest.getLanguage().equals("NL"))
                System.out.println("Client receives service by Dutch CS representative: " + name); 
            else
                passRequestToNextInChain(csRequest, "We provide customer service for EN and NL only");
        }else {
            passRequestToNextInChain(csRequest, "Sorry, all support employees are busy at the moment! Please try again later!");
        }
    }
}

And the English speaking customer support employee:
package com.tasosmartidis.design_patterns_tutorial.chain;

public class CustomerSupportEnglish extends CustomerSupportEmployee { 
    private String name;
    
    public CustomerSupportEnglish(String name) {
        this.name = name;
    }

    public void serveCustomer(CustomerServiceRequest csRequest) {
        if(!this.isEmployeeBusy()) {
            
            if(csRequest.getLanguage().equals("EN"))
                System.out.println("Client receives service by English CS representative: " + name); 
            else
                passRequestToNextInChain(csRequest, "We provide customer service for EN and NL only");
        }else {
            passRequestToNextInChain(csRequest, "Sorry, all support employees are busy at the moment! Please try again later!");
        }
    }           
}

I am showcasing the chain pattern here and focus only in it, but I would prefer to have the factory pattern for selecting between Dutch and English customer support employee and use the chain for passing the request if a receiver (employee) is busy.

Let's now create a requester class, for the objects that require customer support. The requester will have a name and the language in which they wish to be "supported".
package com.tasosmartidis.design_patterns_tutorial.chain;

public class CustomerServiceRequest {

    private String clientName;
    private String language;
    
    public CustomerServiceRequest(String clientName, String language) {
        this.clientName = clientName;
        this.language = language;
    }
    
    public String getClientName() {
        return clientName;
    }
    public void setClientName(String clientName) {
        this.clientName = clientName;
    }
    public String getLanguage() {
        return language;
    }
    public void setLanguage(String language) {
        this.language = language;
    }
}

We are almost there! Let's create a demo scenario, where a customer will request support and the request will be passed in the chain to the appropriate receiver that is currently not busy.
package com.tasosmartidis.design_patterns_tutorial.chain;

public class CustomerSupportDemo {

    public static void main(String[] args) {
        CustomerServiceRequest supportClient = new CustomerServiceRequest("Tasos", "EN");
        
        // Create a few customer support employees
        CustomerSupportEmployee englishSpeaker1 = new CustomerSupportEnglish("Joe");
        CustomerSupportEmployee englishSpeaker2 = new CustomerSupportEnglish("Jane");
        CustomerSupportEmployee dutchSpeaker1 = new CustomerSupportDutch("Anne");
        CustomerSupportEmployee dutchSpeaker2 = new CustomerSupportDutch("Tessa");
        
        // Define the chain of command
        dutchSpeaker1.setNextInChain(dutchSpeaker2);
        dutchSpeaker2.setNextInChain(englishSpeaker1);
        englishSpeaker1.setNextInChain(englishSpeaker2);
        
        // Make first in chain English speaking employee busy so he has to pass the request
        englishSpeaker1.setEmployeeBusy(true);
        
        dutchSpeaker1.serveCustomer(supportClient);
    }
}

All setup, and for the scenario we setup in the demo class above, the request should pass the dutch speaking employees in the chain (Anne, Tessa), and the busy English speaker ("Joe") to be served by the available one ("Jane"). Let's see if it works as expected!


It worked! And this concludes the tutorial on the chain design pattern. The code as always, is available on github.

No comments:

Post a Comment