Chain of Responsibility — Behavioral Design Pattern

When we think about chain of responsibility, it gives some understanding or feeling about what it does or what it suppose to do by it self. But for easiness, will map this into a real world scenario where it’s used in common day to day activities in your company or organization.
Some of you may heard about “chain of command”. Which used in many management structures to split responsibilities among colleagues or co-workers in an organization. By this the organization’s hierarchy is set from the bottom to the top, where who must answer to whom and what type of accountabilities, authorities and decision making powers they get when performing day to day activities.
So, Now you may have some idea about a real world use of the pattern in different domain, other than the programming.
If we move back to our title, the “chain of responsibility” pattern in software designing.
- Decoupling the initiator and receiver
- Runtime process picking strategy
are the main key points of this design pattern. In each responsibility chain object, based on certain criterions different actions are performed.
Let’s think about an example
In Spring world, the servlet filters are commonly used for pre-request and post-request processing. In those situations, the framework gives flexibility to write our own filter and place in the filter chain to do the processing. That is a classic example of chain of responsibility in action.
@Component
public class TestFilter implements Filter { @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { log.info("Host : {}", request.getRemoteHost());
log.info("Remote : {}", request.getRemoteAddr());
chain.doFilter(request, response); // call the next filter
}}
Code Example
We’ll take a sample scenario of a cloud partner monthly bill calculation process. In that case, for a customer there can be multiple sub-cloud providers and services in use. for that, the agent partner should bill under one invoice. So, the bill processing logic in a software design level would be like this.
The following program is a JAVA console based application.
- Create Bill entity.
public class Bill {
private double awsCost;
private double gCloudCost;
private double azureCost;
private double subTotal;
private double discount;
private double total;
...
}
2. The base Handler interface for bill processing.
public interface Handler {
/**
* The next handler reference
*
* @param handler - the handler
*/
void nextHandler(Handler handler);
/**
* The bill processor
*
* @param bill - the bill entity
*/
void process(Bill bill);
}
3. Create individual handlers for each process. Ex : AWSHandler
/**
* AWS related cost handler
*/
public class AWSHandler implements Handler {
private Handler next;
@Override
public void nextHandler(Handler handler) {
next = handler;
}
@Override
public void process(Bill bill) {
// do the AWS cost calculations
bill.setAwsCost(1000);
System.out.println("AWSHandler : done");
// call the next handler
if (next != null) {
next.process(bill);
}
}
}
4. The main initiator would be like.
public class Main {
public static void main(String[] args) {
Bill hostingBill = new Bill();
// create handlers
AWSHandler awsHandler = new AWSHandler();
GCloudHandler gCloudHandler = new GCloudHandler();
AzureHandler azureHandler = new AzureHandler();
DiscountHandler discountHandler = new DiscountHandler();
// set next hop handlers
awsHandler.nextHandler(gCloudHandler);
gCloudHandler.nextHandler(azureHandler);
azureHandler.nextHandler(discountHandler);
// trigger the calculation
awsHandler.process(hostingBill);
System.out.println("--------------------------------");
System.out.println("Monthly Hosting Bill");
System.out.println("--------------------------------");
System.out.println("AWS Cost : " + hostingBill.getAwsCost());
System.out.println("Google Cloud Cost : " + hostingBill.getGCloudCost());
System.out.println("Azure Cost : " + hostingBill.getAzureCost());
System.out.println("--------------------------------");
System.out.println("Sub Total : " + hostingBill.getSubTotal());
System.out.println("Discount : " + hostingBill.getDiscount());
System.out.println("Total : " + hostingBill.getTotal());
}
}
The application’s console output.
AWSHandler : done
GCloudHandler : done
AzureHandler : done
DiscountHandler : done
--------------------------------
Monthly Hosting Bill
--------------------------------
AWS Cost : 1000.0
Google Cloud Cost : 1500.0
Azure Cost : 2500.0
--------------------------------
Sub Total : 5000.0
Discount : 250.0
Total : 4750.0
Here’s the link for the source code.
I hope you liked it and got clear understanding about the chain of responsibility design pattern.
Thanks for reading !!…