Tutorial

Chain of Responsibility Design Pattern in Java

Published on August 3, 2022
author

Pankaj

Chain of Responsibility Design Pattern in Java

Chain of responsibility design pattern is one of the behavioral design pattern.

Chain of Responsibility Design Pattern

Chain of Responsibility Design Pattern, Chain of Responsibility Pattern, Chain of Responsibility Pattern Java, Chain of Responsibility Chain of responsibility pattern is used to achieve loose coupling in software design where a request from client is passed to a chain of objects to process them. Then the object in the chain will decide themselves who will be processing the request and whether the request is required to be sent to the next object in the chain or not.

Chain of Responsibility Pattern Example in JDK

Let’s see the example of chain of responsibility pattern in JDK and then we will proceed to implement a real life example of this pattern. We know that we can have multiple catch blocks in a try-catch block code. Here every catch block is kind of a processor to process that particular exception. So when any exception occurs in the try block, its send to the first catch block to process. If the catch block is not able to process it, it forwards the request to next object in chain i.e next catch block. If even the last catch block is not able to process it, the exception is thrown outside of the chain to the calling program.

Chain of Responsibility Design Pattern Example

One of the great example of Chain of Responsibility pattern is ATM Dispense machine. The user enters the amount to be dispensed and the machine dispense amount in terms of defined currency bills such as 50$, 20$, 10$ etc. If the user enters an amount that is not multiples of 10, it throws error. We will use Chain of Responsibility pattern to implement this solution. The chain will process the request in the same order as below image. Chain of Responsibility Pattern, Chain of Responsibility Design Pattern Note that we can implement this solution easily in a single program itself but then the complexity will increase and the solution will be tightly coupled. So we will create a chain of dispense systems to dispense bills of 50$, 20$ and 10$.

Chain of Responsibility Design Pattern - Base Classes and Interface

We can create a class Currency that will store the amount to dispense and used by the chain implementations. Currency.java

package com.journaldev.design.chainofresponsibility;

public class Currency {

	private int amount;
	
	public Currency(int amt){
		this.amount=amt;
	}
	
	public int getAmount(){
		return this.amount;
	}
}

The base interface should have a method to define the next processor in the chain and the method that will process the request. Our ATM Dispense interface will look like below. DispenseChain.java

package com.journaldev.design.chainofresponsibility;

public interface DispenseChain {

	void setNextChain(DispenseChain nextChain);
	
	void dispense(Currency cur);
}

Chain of Responsibilities Pattern - Chain Implementations

We need to create different processor classes that will implement the DispenseChain interface and provide implementation of dispense methods. Since we are developing our system to work with three types of currency bills - 50$, 20$ and 10$, we will create three concrete implementations. Dollar50Dispenser.java

package com.journaldev.design.chainofresponsibility;

public class Dollar50Dispenser implements DispenseChain {

	private DispenseChain chain;
	
	@Override
	public void setNextChain(DispenseChain nextChain) {
		this.chain=nextChain;
	}

	@Override
	public void dispense(Currency cur) {
		if(cur.getAmount() >= 50){
			int num = cur.getAmount()/50;
			int remainder = cur.getAmount() % 50;
			System.out.println("Dispensing "+num+" 50$ note");
			if(remainder !=0) this.chain.dispense(new Currency(remainder));
		}else{
			this.chain.dispense(cur);
		}
	}

}

Dollar20Dispenser.java

package com.journaldev.design.chainofresponsibility;

public class Dollar20Dispenser implements DispenseChain{

	private DispenseChain chain;
	
	@Override
	public void setNextChain(DispenseChain nextChain) {
		this.chain=nextChain;
	}

	@Override
	public void dispense(Currency cur) {
		if(cur.getAmount() >= 20){
			int num = cur.getAmount()/20;
			int remainder = cur.getAmount() % 20;
			System.out.println("Dispensing "+num+" 20$ note");
			if(remainder !=0) this.chain.dispense(new Currency(remainder));
		}else{
			this.chain.dispense(cur);
		}
	}

}

Dollar10Dispenser.java

package com.journaldev.design.chainofresponsibility;

public class Dollar10Dispenser implements DispenseChain {

	private DispenseChain chain;
	
	@Override
	public void setNextChain(DispenseChain nextChain) {
		this.chain=nextChain;
	}

	@Override
	public void dispense(Currency cur) {
		if(cur.getAmount() >= 10){
			int num = cur.getAmount()/10;
			int remainder = cur.getAmount() % 10;
			System.out.println("Dispensing "+num+" 10$ note");
			if(remainder !=0) this.chain.dispense(new Currency(remainder));
		}else{
			this.chain.dispense(cur);
		}
	}

}

The important point to note here is the implementation of dispense method. You will notice that every implementation is trying to process the request and based on the amount, it might process some or full part of it. If one of the chain not able to process it fully, it sends the request to the next processor in chain to process the remaining request. If the processor is not able to process anything, it just forwards the same request to the next chain.

Chain of Responsibilities Design Pattern - Creating the Chain

This is a very important step and we should create the chain carefully, otherwise a processor might not be getting any request at all. For example, in our implementation if we keep the first processor chain as Dollar10Dispenser and then Dollar20Dispenser, then the request will never be forwarded to the second processor and the chain will become useless. Here is our ATM Dispenser implementation to process the user requested amount. ATMDispenseChain.java

package com.journaldev.design.chainofresponsibility;

import java.util.Scanner;

public class ATMDispenseChain {

	private DispenseChain c1;

	public ATMDispenseChain() {
		// initialize the chain
		this.c1 = new Dollar50Dispenser();
		DispenseChain c2 = new Dollar20Dispenser();
		DispenseChain c3 = new Dollar10Dispenser();

		// set the chain of responsibility
		c1.setNextChain(c2);
		c2.setNextChain(c3);
	}

	public static void main(String[] args) {
		ATMDispenseChain atmDispenser = new ATMDispenseChain();
		while (true) {
			int amount = 0;
			System.out.println("Enter amount to dispense");
			Scanner input = new Scanner(System.in);
			amount = input.nextInt();
			if (amount % 10 != 0) {
				System.out.println("Amount should be in multiple of 10s.");
				return;
			}
			// process the request
			atmDispenser.c1.dispense(new Currency(amount));
		}

	}

}

When we run above application, we get output like below.

Enter amount to dispense
530
Dispensing 10 50$ note
Dispensing 1 20$ note
Dispensing 1 10$ note
Enter amount to dispense
100
Dispensing 2 50$ note
Enter amount to dispense
120
Dispensing 2 50$ note
Dispensing 1 20$ note
Enter amount to dispense
15
Amount should be in multiple of 10s.

Chain of Responsibilities Design Pattern Class Diagram

Our ATM dispense example of chain of responsibility design pattern implementation looks like below image. Chain of Responsibility, Chain of Responsibility Design Pattern, Chain of Responsibility Pattern Class Diagram

Chain of Responsibility Design Pattern Important Points

  • Client doesn’t know which part of the chain will be processing the request and it will send the request to the first object in the chain. For example, in our program ATMDispenseChain is unaware of who is processing the request to dispense the entered amount.
  • Each object in the chain will have it’s own implementation to process the request, either full or partial or to send it to the next object in the chain.
  • Every object in the chain should have reference to the next object in chain to forward the request to, its achieved by java composition.
  • Creating the chain carefully is very important otherwise there might be a case that the request will never be forwarded to a particular processor or there are no objects in the chain who are able to handle the request. In my implementation, I have added the check for the user entered amount to make sure it gets processed fully by all the processors but we might not check it and throw exception if the request reaches the last object and there are no further objects in the chain to forward the request to. This is a design decision.
  • Chain of Responsibility design pattern is good to achieve lose coupling but it comes with the trade-off of having a lot of implementation classes and maintenance problems if most of the code is common in all the implementations.

Chain of Responsibility Pattern Examples in JDK

  • java.util.logging.Logger#log()
  • javax.servlet.Filter#doFilter()

Thats all for the Chain of Responsibility design pattern, I hope you liked it and its able to clear your understanding on this design pattern.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Pankaj

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
JournalDev
DigitalOcean Employee
DigitalOcean Employee badge
July 18, 2013

I savor, cause I discovered exactly what I was having a look for. You’ve ended my 4 day long hunt! God Bless you man. Have a great day. Bye

- Graphic Design Singapore

    JournalDev
    DigitalOcean Employee
    DigitalOcean Employee badge
    October 23, 2013

    Hi, Can you provide the download link for this example.

    - jawahar

      JournalDev
      DigitalOcean Employee
      DigitalOcean Employee badge
      January 6, 2014

      Getting the below exception … Exception in thread “main” java.lang.NullPointerException at com.chain.responsibility.dispenser.HundredDollarDispenser.dispense(HundredDollarDispenser.java:26) at com.chain.responsibility.dispenser.FiftyDollarDispenser.dispense(FiftyDollarDispenser.java:30) at com.chain.responsibility.dispenser.ATMDispenseChain.main(ATMDispenseChain.java:33)

      - Vijayendran T R

        JournalDev
        DigitalOcean Employee
        DigitalOcean Employee badge
        February 6, 2014

        Hi… Nice tutorial… Just 1 suggestion setNextChain() would have been moved to DispenseChain abstract class instead of keeping DispenseChain as abstract class and overriding setNextChain() in all the concrete classes…

        - kushi

          JournalDev
          DigitalOcean Employee
          DigitalOcean Employee badge
          June 16, 2014

          Good example. I’d like to point out one thing though. The pattern per GoF definition says that ‘Only one object in the chain is supposed to handle a request’. In your example I see handlers($50 and $20) doing the work partially and letting $10 handler do the rest of the job.

          - Gaurav

            JournalDev
            DigitalOcean Employee
            DigitalOcean Employee badge
            July 13, 2014

            After implementing this design pattern for years, i commonly see that there is repeated code in the concrete classes just like the implementation of your dispense methods. The intent of this design pattern is nice, but dont forget the DRY principle and it is a must in my humble opinion. I always use abstract classes for cor design pattern to eliminate duplicate code.

            - killer

              JournalDev
              DigitalOcean Employee
              DigitalOcean Employee badge
              December 24, 2014

              Mate, once again, check your English! It’s loose coupling. Furthermore, Gaurav, you’re right about only one object handling the request. That would be what’s called a pure implementation. On the other hand, there’s no real problem to let the request go through the entire tree. Another point, which is not discussed in this article, is that you may set or change the next handler during runtime. You also may not know beforehand which are the handlers that should be used, allowing the client to set them as desired. As an example, you could have many Validator classes which can be called in a certain order. But that depends on the validation. So you apply CoR and make good use out of the possibility of combining different validators ordered in so many different ways. Suppose you want to validate an email address. You need to check if the e-mail is correctly formed, if it exists, and if contains bad words. To do this job, you may have three different classes, and you can arrange them in any order - so you might as well let the client decide its own priority.

              - You Know

                JournalDev
                DigitalOcean Employee
                DigitalOcean Employee badge
                June 26, 2015

                Thank you very much Pankaj. The tutorial on Design Patterns was very helpful. I could get a brief overview of Design Patterns and one more good point is that you have taken real world examples to demonstrate. In some part of the tutorial you have mentioned that one design pattern can be combined with the other to make it more efficient, it would be helpful if you post some samples on it. Great work buddy. Thanks a lot.

                - Bharath

                  JournalDev
                  DigitalOcean Employee
                  DigitalOcean Employee badge
                  July 8, 2015

                  Easy to understand. Thank you

                  - Anusharmila

                    JournalDev
                    DigitalOcean Employee
                    DigitalOcean Employee badge
                    April 23, 2016

                    nice and clear example. Thanks

                    - Ricky Walia

                      Try DigitalOcean for free

                      Click below to sign up and get $200 of credit to try our products over 60 days!

                      Sign up

                      Join the Tech Talk
                      Success! Thank you! Please check your email for further details.

                      Please complete your information!

                      Become a contributor for community

                      Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

                      DigitalOcean Documentation

                      Full documentation for every DigitalOcean product.

                      Resources for startups and SMBs

                      The Wave has everything you need to know about building a business, from raising funding to marketing your product.

                      Get our newsletter

                      Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

                      New accounts only. By submitting your email you agree to our Privacy Policy

                      The developer cloud

                      Scale up as you grow — whether you're running one virtual machine or ten thousand.

                      Get started for free

                      Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

                      *This promotional offer applies to new accounts only.