HowToDoInJava

  • Python
  • Java
  • Spring Boot
  • Dark Mode
Home / Design Patterns / Behavioral / Chain of Responsibility Design Pattern

Chain of Responsibility Design Pattern

The Chain of Responsibility is known as a behavioral pattern. The main objective of this pattern is that it avoids coupling the sender of the request to the receiver, giving more than one object the opportunity to handle the request. The core logic defined by GoF is :

"Gives more than one object an opportunity to handle a request by linking receiving objects together."

Chain of Responsibility allows a number of classes to attempt to handle a request, independently of any other object along the chain. Once the request is handled, it completes it’s journey through the chain.

Extra handlers can be added or removed from chain without modifying the logic inside any of concrete handler.

Sections in this post:

Suggested usage
Participants in the solution
Sample problem to be solved
Proposed solution
Class diagram of participants
Sourcecode of participants
Test the application
Download sourecode link
Reference implementations in JDK

Suggested usage

This pattern is recommended when multiple objects can handle a request and the handler doesn’t have to be a specific object. Also, handler is determined at runtime. Please note that that a request not handled at all by any handler is a valid use case.

For example, event handling mechanism in windows OS where events can be generated from either mouse, keyboard or some automatic generated events. All such events can be handled by multiple handlers and correct handler is found on runtime.

More general exampe can be a service request to call center. This request can be handled at front desk level, supervisor level or any higher level. Correct handler of request is only known at runtime when request is traversing at various levels. We will solve this scenario in this post.

Participants in the solution

1) Handler : This can be an interface which will primarily recieve the request and dispatches the request to chain of handlers. It has reference of only first handler in the chain and does not know anything about rest of the handlers.

2) Concrete handlers : These are actual handlers of the request chained in some sequential order.

3) Client : Originator of request and this will access the handler to handle it.

participants_of_chain_of_responsibility-4978976
Participants in chain of responsibility

Sample problem to be solved

The problem statement is to design a system for support service system consisting of front desk, supervisor, manager and director. Any client can call to front desk and will ask for a solution. If front desk is able to solve the issue, it will; otherwise will pass to supervisor. Similarly, supervisor will try to solve the issue and if he is able to then he will solve; else pass to manager. Same way, manager will either solve the issue or pass to director. Director will either solve the issue or reject it.

Proposed solution

Above problem is a good candidate for using chain of responsibility pattern. We can define the handler at each level i.e. support desk, supervisor, manager and director. Then we can define a chain for handling the support request. This chain must follow the sequence:

Support desk > supervisor > manager > director

Above chain can be managed using programmatic solutions in java also, but in this tutorial i am using spring for injecting the dependencies and thus forming this chain. Also, System will first assign the request to front desk only.

Class diagram of participants

I have draw the structure of all entities involved in the solution as below.

chainofresponsibility_classdiagram-2377740
Support service system : class diagram

Sourcecode of participants

Below is the sourcecode of all participants involved in support service implementation using chain of responsibility design pattern:

ServiceLevel.java

package com.howtodoinjava;

public enum ServiceLevel
{
	LEVEL_ONE, LEVEL_TWO, LEVEL_THREE, LEVEL_FOUR, INVALID_REQUEST
}

ServiceRequest.java

package com.howtodoinjava.data;

import com.howtodoinjava.ServiceLevel;

public class ServiceRequest {

	private ServiceLevel type;
	private String conclusion = null;

	public ServiceLevel getType() {
		return type;
	}
	public void setType(ServiceLevel type) {
		this.type = type;
	}
	public String getConclusion() {
		return conclusion;
	}
	public void setConclusion(String conclusion) {
		this.conclusion = conclusion;
	}
}

SupportServiceItf.java

package com.howtodoinjava.handler;

import com.howtodoinjava.data.ServiceRequest;

public interface SupportServiceItf
{
	public void handleRequest(ServiceRequest request);
}

SupportService.java

package com.howtodoinjava.handler;

import com.howtodoinjava.data.ServiceRequest;

public class SupportService implements SupportServiceItf {

	private SupportServiceItf handler = null;

	public SupportServiceItf getHandler() {
		return handler;
	}

	public void setHandler(SupportServiceItf handler) {
		this.handler = handler;
	}

	@Override
	public void handleRequest(ServiceRequest request) {
		handler.handleRequest(request);
	}
}

FrontDeskSupport.java

package com.howtodoinjava.handler;

import com.howtodoinjava.ServiceLevel;
import com.howtodoinjava.data.ServiceRequest;

public class FrontDeskSupport implements SupportServiceItf {

	private SupportServiceItf next = null;
	public SupportServiceItf getNext() {
		return next;
	}
	public void setNext(SupportServiceItf next) {
		this.next = next;
	}

	@Override
	public void handleRequest(ServiceRequest service) {
		if(service.getType() == ServiceLevel.LEVEL_ONE)
		{
			service.setConclusion("Front desk solved level one reuqest !!");
		}
		else
		{
			if(next != null){
				next.handleRequest(service);
			}
			else
			{
				throw new IllegalArgumentException("No handler found for :: " + service.getType());
			}
		}
	}
}

SupervisorSupport.java

package com.howtodoinjava.handler;

import com.howtodoinjava.ServiceLevel;
import com.howtodoinjava.data.ServiceRequest;

public class SupervisorSupport implements SupportServiceItf {

	private SupportServiceItf next = null;
	public SupportServiceItf getNext() {
		return next;
	}
	public void setNext(SupportServiceItf next) {
		this.next = next;
	}

	@Override
	public void handleRequest(ServiceRequest request) {
		if(request.getType() == ServiceLevel.LEVEL_TWO)
		{
			request.setConclusion("Supervisor solved level two reuqest !!");
		}
		else
		{
			if(next != null){
				next.handleRequest(request);
			}
			else
			{
				throw new IllegalArgumentException("No handler found for :: " + request.getType());
			}
		}
	}
}

ManagerSupport.java

package com.howtodoinjava.handler;

import com.howtodoinjava.ServiceLevel;
import com.howtodoinjava.data.ServiceRequest;

public class ManagerSupport implements SupportServiceItf {

	private SupportServiceItf next = null;
	public SupportServiceItf getNext() {
		return next;
	}
	public void setNext(SupportServiceItf next) {
		this.next = next;
	}

	@Override
	public void handleRequest(ServiceRequest request) {
		if(request.getType() == ServiceLevel.LEVEL_THREE)
		{
			request.setConclusion("Manager solved level three reuqest !!");
		}
		else
		{
			if(next != null){
				next.handleRequest(request);
			}
			else
			{
				throw new IllegalArgumentException("No handler found for :: " + request.getType());
			}
		}
	}
}

DirectorSupport.java

package com.howtodoinjava.handler;

import com.howtodoinjava.ServiceLevel;
import com.howtodoinjava.data.ServiceRequest;

public class DirectorSupport implements SupportServiceItf {

	private SupportServiceItf next = null;
	public SupportServiceItf getNext() {
		return next;
	}
	public void setNext(SupportServiceItf next) {
		this.next = next;
	}

	@Override
	public void handleRequest(ServiceRequest request) {
		if(request.getType() == ServiceLevel.LEVEL_FOUR)
		{
			request.setConclusion("Director solved level four reuqest !!");
		}
		else
		{
			if(next != null){
				next.handleRequest(request);
			}
			else
			{
				request.setConclusion("You problem is none of our business");
				throw new IllegalArgumentException("You problem is none of our business :: " + request.getType());
			}
		}
	}
}

applicationConfig.xml

<?xml  version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:lang="http://www.springframework.org/schema/lang"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop/ http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context/ http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/jee/ http://www.springframework.org/schema/jee/spring-jee.xsd
        http://www.springframework.org/schema/lang/ http://www.springframework.org/schema/lang/spring-lang.xsd
        http://www.springframework.org/schema/tx/ http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/util/ http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="supportService" class="com.howtodoinjava.handler.SupportService">
        <property name="handler" ref="frontDeskSupport"></property>
    </bean>

    <bean id="frontDeskSupport" class="com.howtodoinjava.handler.FrontDeskSupport">
        <property name="next" ref="supervisorSupport"></property>
    </bean>
    <bean id="supervisorSupport" class="com.howtodoinjava.handler.SupervisorSupport">
        <property name="next" ref="managerSupport"></property>
    </bean>
    <bean id="managerSupport" class="com.howtodoinjava.handler.ManagerSupport">
        <property name="next" ref="directorSupport"></property>
    </bean>
    <bean id="directorSupport" class="com.howtodoinjava.handler.DirectorSupport"></bean>

</beans>

Test the application

I will pass various level of support requests down the chain and they will be handled by correct level. Any invalid request will be rejected as planned for.

package com.howtodoinjava;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.howtodoinjava.data.ServiceRequest;
import com.howtodoinjava.handler.SupportService;

public class TestChainOfResponsibility {
	public static void main(String[] args)
	{
		ApplicationContext context = new ClassPathXmlApplicationContext("application-config.xml");
		SupportService supportService = (SupportService) context.getBean("supportService");

		ServiceRequest request = new ServiceRequest();
		request.setType(ServiceLevel.LEVEL_ONE);
		supportService.handleRequest(request);
		System.out.println(request.getConclusion());

		request = new ServiceRequest();
		request.setType(ServiceLevel.LEVEL_THREE);
		supportService.handleRequest(request);
		System.out.println(request.getConclusion());

		request = new ServiceRequest();
		request.setType(ServiceLevel.INVALID_REQUEST);
		supportService.handleRequest(request);
		System.out.println(request.getConclusion());
	}
}

<strong>Output:</strong>

Front desk solved level one reuqest !!
Manager solved level three reuqest !!
Exception in thread "main" java.lang.IllegalArgumentException: You problem is none of our business :: INVALID_REQUEST

To download the sourecode of above example application, click on below link.

Sourcecode download

Reference implementations in JDK

  • javax.servlet.Filter#doFilter()

The doFilter method of the Filter is called by the container each time a request/response pair is passed through the chain due to a client request for a resource at the end of the chain. The FilterChain passed in to this method allows the Filter to pass on the request and response to the next entity in the chain.

  • java.util.logging.Logger#log

If the logger is currently enabled for the given message level then the given message is forwarded to all the registered output Handler objects.

I hope that this post post has added some knowledge in your understanding of chain of responsibility pattern. If you have any query, post a comment.

Happy Learning !!

Was this post helpful?

Let us know if you liked the post. That’s the only way we can improve.

Share this:

  • Twitter
  • Facebook
  • LinkedIn
  • Reddit

About Lokesh Gupta

A family guy with fun loving nature. Love computers, programming and solving everyday problems. Find me on Facebook and Twitter.

Feedback, Discussion and Comments

  1. Robert Cutright

    March 24, 2020

    Very helpful guide!

    I’d also like to add that anytime you are repeating code, it is worth the time for further evaluation.

    The support services… DirectorSupport, FrontDeskSupport, ManagerSupport, SupervisorSupport could all be lifted to an abstract class.

    public abstract class AbstractSupport implements ISupportService
    {
        private ISupportService next = null;
    
        private final ServiceLevel serviceLevel;
    
        public AbstractSupport(ServiceLevel serviceLevel) {
            this.serviceLevel = serviceLevel;
        }
    
        public boolean isServiceLevel(ServiceLevel serviceLevel) {
            return this.serviceLevel == serviceLevel;
        }
    
        public final ISupportService getNext()
        {
            return next;
        }
    
        public final void setNext(ISupportService next)
        {
            this.next = next;
        }
    
        public void handleRequest(ServiceRequest request) {
            if (isServiceLevel(request.getType())) {
                handleRequestImpl(request);
            } else {
                if (getNext() != null) {
                    getNext().handleRequest(request);
                }
                else
                {
                    request.setConclusion("Your problem is none of our business");
                    throw new IllegalArgumentException("You problem is none of our business :: " + request.getType());
                }
            }
        }
    
        public abstract void handleRequestImpl(ServiceRequest request);
    }
    

    By doing this you can simplify the required code in the subclasses:

    public class FrontDeskSupport extends AbstractSupport
    {
        public FrontDeskSupport()
        {
            super(ServiceLevel.LEVEL_ONE);
        }
    
        public void handleRequestImpl(ServiceRequest request)
        {
            request.setConclusion("Front desk handled request - Level: " + request.getType());
        }
    }
    
    public class SupervisorSupport extends AbstractSupport
    {
        public SupervisorSupport()
        {
            super(ServiceLevel.LEVEL_TWO);
        }
    
        public void handleRequestImpl(ServiceRequest request)
        {
            request.setConclusion("Supervisor support handled request - Level: " + request.getType());
        }
    }
    
    public class ManagerSupport extends AbstractSupport
    {
        public ManagerSupport()
        {
            super(ServiceLevel.LEVEL_THREE);
        }
    
        public void handleRequestImpl(ServiceRequest request)
        {
            request.setConclusion("Manager support handled request - Level: " + request.getType());
        }
    }
    
    
    public class DirectorSupport extends AbstractSupport {
    
        public DirectorSupport()
        {
            super(ServiceLevel.LEVEL_FOUR);
        }
    
        public void handleRequestImpl(ServiceRequest request)
        {
            request.setConclusion("Director handled request - Level: " + request.getType());
        }
    }
    

    Of course, this could be even further expanded and made more dynamic by specifying the service level types in the config XML file for each support class. I’ll leave that to the reader’s own ideas.

    • Lokesh Gupta

      March 24, 2020

      Thanks for sharing your thoughts. Much appreciated !!

  2. Thangamma

    December 16, 2019

    Hi Lokesh,
    Thank you so much for the explanation.
    Why is the SupportService class implementing the “SupportServiceItf ” interface ? Can’t we directly inject the object of SupportService and use it , wherein in supportService class takes care of directing the request to frontDeskService and so on as you mentioned. Is it the pattern that we should follow in Chain of responsibility pattern ?

  3. vishesh

    August 26, 2017

    Why I need COR pattern , However I can do the same thing with switch statement as well?

    • Lokesh Gupta

      August 26, 2017

      In switch statement, only one block handle the request. In COR, multiple handlers also can take part in request processing and form the complete response object.

      • vishesh

        August 26, 2017

        Nice explanation Thanks

  4. Allan Caine

    November 12, 2013

    Also, the chain of responsibility is sometimes better handled with the handleRequest(…) method returning a boolean: true if the request is handled, false otherwise.

    public interface SupportServiceItf
    {
    public boolean handleRequest(ServiceRequest request);
    }

    Then, a class possessing a Collection of the handlers, the call is simply

    boolean isHandled = false;

    for(SupportServiceItf handler : collectionOfHanders){
    isHandled = handler.handle(serviceRequest);
    if(isHandled){
    break;
    }
    }

    if(!isHandled){
    // something may need to be done because the request never got handled
    }

    This also avoids handlers being aware of each other in what is essentially a singly linked list. I believe that it is generally better that the handlers be unaware of each other’s existence and be isolated from each other.

    There is also the additional difficulty that the classes have paired getters and setters: getNext()/setNext(…) and getHandler)/setHandler(…). Once a field of a class is made read/write, the field is now public. For safety, I believe that this example would be made better if the classes were made immutable.

    However, if the approach of putting the handler in a Collection were used, then the handler code is simplified. Any re-arrangements can be done by a management class, which I believe to be a much more flexible approach.

    • Lokesh Gupta

      November 12, 2013

      I will try to work on your suggestions and update you accordingly.

      • RAMJANE

        January 5, 2014

        But if Management class will be delegating responsibility from one class t another then delegator design pattern or kind of factory design pattern

        Agree there is tight coupling in class that is not good.We have to put example that will has High cohesion and low Coupling.

        one more Question Struts 2 is based on this pattern??/

        • Lokesh Gupta

          January 5, 2014

          I have agreed only on “immutable” part. It makes sense to me make handlers immutable. I also feel that Management class will not add any benefit here.

          Tight coupling? I will not agree easily. This design has lots of benefit e.g. directly passing request to certain handler and a request handled by even multiple handlers.(You may come across this situation also where request may need multiple handlers.) In code there is no references to other classes. Everything is done in configuration file. Where is tight coupling? You have configure your system somewhere, right?

          I really do not find struts 2 a good candidate for example of this pattern. Reason? CoR pattern has multiple handlers and one of them handle the request. In struts2, actual handler is Action class and interceptors actually works as decorators or observers and sometimes doing some more work. They are more file filters in servlet technology. They do not handle the request. So, I will prefer not to mention struts 2 as example of chain of responsibility pattern.

  5. Allan Caine

    November 12, 2013

    The example would be better by reconsidering the design of the ServiceRequest class. By having both a get a set method for each of its private fields type and conclusion, its encapsulation is broken. The fields are effectively public. I believe that the ServiceRequest ought to be made invariant. The fields are final and private. They are set through the constructor. The set methods are removed, leaving only the get methods. As it stands, and handler could accidentally change the service request resulting in an error which requires debugging.

    • Lokesh Gupta

      November 12, 2013

      I agree. No need to have setType() in ServiceRequest.java. We can pass it in constructor. In fact it’s good idea.

  6. Suresh

    October 14, 2013

    I have couple of Questions.
    1 Who will define next level.
    2. What will be the flow of request. FrontDesk -> Manager or FrontDesk -> SupportService -> Manger ?

    • Lokesh Gupta

      October 14, 2013

      Answers:
      1) Developer will define per business rules.
      2) With current implementation: Front desk > supervisor > manager > direct support. Depends on service level.

      • Suresh

        October 14, 2013

        Lets say in our application we have 5 different type of chains and those may got change on frequent basics so as per your implantation we have to update next level for all the supervisor each time… if we are not using Spring in that app…
        2. What will be implementations for 5 chains..

        • Lokesh Gupta

          October 14, 2013

          How first chain will be different from other four chains. Sequence.. right?? But sequence doesn’t matter here. Concept is that every object in chain will get it’s chance to handle the request. Whoever is capable, will handle it. Otherwise just forward to next handler and let him try.

    • JL

      May 28, 2015

      I have reed the comments but did not understand this point:
      “1 Who will define next level”

      If we define:

      ServiceRequest request = new ServiceRequest();
      request.setType(ServiceLevel.LEVEL_THREE);
      supportService.handleRequest(request);
      System.out.println(request.getConclusion());

      Does the execution of the application start on FrontDeskSupport (LEVEL_ONE) then to SupervisorSupport (LEVEL_TWO) and finally ManagerSupport (LEVEL_THREE) in this order?

      if the enum ServiceLevel
      {
      LEVEL_FOUR, LEVEL_THREE, LEVEL_TWO, LEVEL_ONE

      will the execution be LEVEL_FOUR, LEVEL_THREE, LEVEL_TWO, LEVEL_ONE?

      Thank you

      • Lokesh Gupta

        May 28, 2015

        Next will be defined through configuration as given in applicationConfig.xml file.

        • JL

          May 29, 2015

          Thank you

  7. mankeomorakort

    June 25, 2013

    useful article

  8. hamid samani (@hamid1129)

    April 22, 2013

    great post, thank you 🙂

Comments are closed on this article!

Search Tutorials

GoF Design Patterns

  • Introduction
  • Creational Patterns
    • Singleton
    • Builder
    • Factory
    • Abstract Factory
    • Prototype
  • Behavioral Patterns
    • Chain of Responsibility
    • Command
    • Iterator Design Pattern
    • Mediator
    • Memento
    • Observer
    • State
    • Strategy
    • Template Method
    • Visitor
  • Structural Patterns
    • Adapter
    • Bridge
    • Composite
    • Decorator
    • Facade
    • Flyweight
    • Proxy

Design Principles

  • SOLID Principles
  • Open closed principle
  • Single responsibility principle

Meta Links

  • About Me
  • Contact Us
  • Privacy policy
  • Advertise
  • Guest and Sponsored Posts

Recommended Reading

  • 10 Life Lessons
  • Secure Hash Algorithms
  • How Web Servers work?
  • How Java I/O Works Internally?
  • Best Way to Learn Java
  • Java Best Practices Guide
  • Microservices Tutorial
  • REST API Tutorial
  • How to Start New Blog

Copyright © 2020 · HowToDoInjava.com · All Rights Reserved. | Sitemap

  • Java 15 New Features
  • Sealed Classes and Interfaces
  • EdDSA (Ed25519 / Ed448)