Chain of responsibility design pattern is one of the behavioral design pattern.
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.
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.
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. 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$.
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);
}
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.
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.
Our ATM dispense example of chain of responsibility design pattern implementation looks like below image.
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.
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.
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
Hi, Can you provide the download link for this example.
- jawahar
There is no download link, its simple java classes. You can copy paste the code and run it.
- Pankaj
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
Problem is we don’t have setNextPattern for the last level
- Anbarasan
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
By having setNextChain() as abstract method, we are forcing subclasses classes to provide implementation for that. For example purpose implementation is simple but there might be cases where some logic is involved for this. Yes if it’s simple as this, we can move it to abstract class. It’s a design decision and should be based on project requirements.
- Pankaj
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
I think I may be wrong coz GoF also says that - Use CoR when more than one object may handle the request…
- Gaurav
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
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
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
Yes this is very easy to follow and with real world examples. Thanks for sharing.
- Muhammad
Examples are great trying to understand where would codes be put in at
- Ron
Easy to understand. Thank you
- Anusharmila
nice and clear example. Thanks
- Ricky Walia
Good Example and quiet easy to understand the design pattern
- Karthik Garrepally
Thanks Karthik for nice words.
- Pankaj
I liked the Explanation.It was very crisp and clear
- Vaibhav M Nalwad
You gave a crisp and Clear Explanation
- Vaibhav M Nalwad
Great example… You Rock always, Pankaj…!
- Jigar Jarsania
Nice article. Why don’t you check if the next chain is set before to call his method dispense()? Your example doesn’t throw a null pointer exception just because you assert that the entered value is a multiple of 10. But this is an information that the 10DollarDispenser doesn’t know.
- Tommaso Resti
Thanks a lot mahn!! Gave me a clear cut view about filter chain! Keep up the good work!
- San Als
Will this program ever return two 50$ (or 20$ or 10$ ) notes. If yes , then can anybody explain how ?
- Priya
Yes it will…The first condition is for (50$) if(cur.getAmount() >= 50){ int num = cur.getAmount()/50; int remainder = cur.getAmount() % 50; System.out.println(“Dispensing “+num+” 50$ note”); consider cur.getAmount() is 156, so num will be 3 notes of $50
- ankit
thank you for your articles.
- Tahere
Awesome article for this concept.
- Krishna
In the Dispence method of Dollar50Dispenser, Dollar20Dispenser and Dollar10Dispenser, else part is not required i guess. Request is already getting processed to the next chain dispense if remainder != 0 . Correct me if i am wrong. And I didnt get the use of always true while loop in the main method. Not required i guess.
- Abdul Qadir
Nice example and well explained.
- Prasanti
public class Dollar10Dispenser implements DispenseChain this.chain.dispense(cur); nullPointException occur
- 现超
The Composition say [0…1] so for Dollar10Dispenser next DispenseChain is not required. you can remove that to avoid Null exception.
- Bibhav
Great blog and perfect explanation with exampl. Thanks
- Rajeev
Great explanations and sample! Thank you bro.
- Ramazan
Nice example but!!! I don´t undert why in main method do you have a while(true).
- isivroes
No particular reason. It’s just so you can try as many examples as you want without having to restart the program every time It’s not necessary for the design pattern.
- Tom
Reading information but im truly a beginner need more knowledge and skills to help me get started here!!
- Ronald Jones
Hello Pankaj Firstly i would like to thank you for this Wonderful article. Just a finding from my end, which i would like to share. Please correct me if i am wrong. I think the else part in all the dispense method is not required. It gives a wrong output. Say for example; see the following steps 1. Say if i entered 60, it will enter the Dollar50 dispense method and it will print (1 note being dispensed - 50 dollar). 2. as the remainder is !=0, it will go to next dispenser in the chain. 3. Say if i entered 50, it will enter Dollar50 dispense method and it will print ( 1 note being dispensed - 5o dollar) 4. as the remainder is 0, it will enter the else part and it will print again the above content (as shown in point 3). I did test in my machine and removed the else part, and it works correctly for any number. Regards Dolly
- Dolly
Can you please specify the code snippet you removed? The code is working fine. If you enter the amount as 50 then the output will be:
Enter amount to dispense 50 Dispensing 1 50$ note Enter amount to dispense
- Pankaj
Great explation! Bro, It helps me to understand the chain of responsibility pattern,Thanks
- Eric
Great post, my only suggestion is to avoid repeat code like in the dispense method, all logic could be in the base class.
- ALEXSANDRO MIRA
after printing the “Amount should be in multiple of 10s.” you could apply continue instead of return. So that the program execution will continue, just a minor suggestion. but nice explanation
- muniappan
Hi Pankaj, great tutorials. Keep going please, with your tutorials because are very useful and educational. I have a question however, here it is. How this would work the same but just for 20 and 50 only Monetaries ? any hint? Thank you
- Andreas
Trying to understand help and assistance is needed. Thank you
- Ron