Using the Chain of Responsibility Design Pattern in Java
Join the DZone community and get the full member experience.
Join For FreeHere, I am with another article on design patterns — Chain of Responsibility. This article will also conclude explanation of all basic design patterns. Please visit my profile to find the other basic design patterns for reference.
Chain of Responsibility Design Pattern
- The Chain of Responsibility Design Pattern is one of the Gang of Four design patterns which creates a chain of receiver objects for a request.
- The Chain of Responsibility pattern is a behavioral pattern which is used to avoid coupling the sender of the request to the receiver and gives more than one receiver object the opportunity to handle the request.
- As per Gang of Four design patterns, the Chain of Responsibility pattern is defined as:
"Gives more than one object an opportunity to handle a request by linking receiving objects together."
- The Chain of Responsibility pattern allows a number of classes to attempt to handle a request independently.
- The Receiver objects of the requests are free from the order and can be use in any order for processing.
- This pattern decouples sender and receiver objects based on type of request.
- This pattern defines a chain of receiver objects having the responsibility, depending on run-time conditions, to either handle a request or forward it to the next receiver on the chain.
- This pattern helps us avoiding coupling of sender and receiver objects of a requests and allows us to have more than one receiver as well for the request.
- ATM withdrawal using different currency notes is one of the great example of Chain of Responsibility pattern.
- Using different types of Loggers in our software is another example of the pattern.
- A call to technical support at different level of discussion is also a good example.
ATM Money Dispenser Using Chain of Responsibility Design Pattern
Let's define a class to hold the amount to withdraw first. Here's the code for PaperCurrency class:
package org.trishinfotech.responsibility;
public class PaperCurrency {
protected int amount;
public PaperCurrency(int amount) {
super();
this.amount = amount;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
}
Now lets define a dispenser abstract class with two main purpose:
- Process the dispense for a specific face-value of currency note.
- Go to another dispenser for processing smaller face value of currency note.
Here's the code for PaperCurrencyDispenser abstract class:
xxxxxxxxxx
package org.trishinfotech.responsibility;
public abstract class PaperCurrencyDispenser {
protected PaperCurrencyDispenser nextDispenser;
public void setNextDispenser(PaperCurrencyDispenser nextDispenser) {
this.nextDispenser = nextDispenser;
}
public abstract void dispense(PaperCurrency currency);
}
Here's the code for HundredDispenser class:
xxxxxxxxxx
package org.trishinfotech.responsibility;
public class HundredDispenser extends PaperCurrencyDispenser {
public HundredDispenser() {
super();
}
public void dispense(PaperCurrency currency) {
if (currency != null) {
int amount = currency.getAmount();
int remainder = amount;
if (amount >= 100) {
int count = amount / 100;
remainder = amount % 100;
System.out.printf("Dispensing '%d' 100$ currency note.\n", count);
}
if (remainder > 0 && this.nextDispenser != null) {
this.nextDispenser.dispense(new PaperCurrency(remainder));
}
}
}
}
Here's the code for FiftyDispenser class:
xxxxxxxxxx
package org.trishinfotech.responsibility;
public class FiftyDispenser extends PaperCurrencyDispenser {
public FiftyDispenser() {
super();
}
public void dispense(PaperCurrency currency) {
if (currency != null) {
int amount = currency.getAmount();
int remainder = amount;
if (amount >= 50) {
int count = amount / 50;
remainder = amount % 50;
System.out.printf("Dispensing '%d' 50$ currency note.\n", count);
}
if (remainder > 0 && this.nextDispenser != null) {
this.nextDispenser.dispense(new PaperCurrency(remainder));
}
}
}
}
Here's the code for TwentyDispenser class:
xxxxxxxxxx
package org.trishinfotech.responsibility;
public class TwentyDispenser extends PaperCurrencyDispenser {
public TwentyDispenser() {
super();
}
public void dispense(PaperCurrency currency) {
if (currency != null) {
int amount = currency.getAmount();
int remainder = amount;
if (amount >= 20) {
int count = amount / 20;
remainder = amount % 20;
System.out.printf("Dispensing '%d' 20$ currency note.\n", count);
}
if (remainder > 0 && this.nextDispenser != null) {
this.nextDispenser.dispense(new PaperCurrency(remainder));
}
}
}
}
Here's the code for TenDispenser class:
xxxxxxxxxx
package org.trishinfotech.responsibility;
public class TenDispenser extends PaperCurrencyDispenser {
public TenDispenser() {
super();
}
public void dispense(PaperCurrency currency) {
if (currency != null) {
int amount = currency.getAmount();
int remainder = amount;
if (amount >= 10) {
int count = amount / 10;
remainder = amount % 10;
System.out.printf("Dispensing '%d' 10$ currency note.\n", count);
}
if (remainder > 0 && this.nextDispenser != null) {
this.nextDispenser.dispense(new PaperCurrency(remainder));
}
}
}
}
Now we will define the ATM withdrawal process in order to define the use of paper currency dispenser. We will arrange the paper currency dispensers in higher to lower face value order.
Here's the code for ATMWithdrawal class:
xxxxxxxxxx
package org.trishinfotech.responsibility;
public class ATMWithdrawal {
protected static PaperCurrencyDispenser hundredDispenser = new HundredDispenser();
protected static PaperCurrencyDispenser fiftyDispenser = new FiftyDispenser();
protected static PaperCurrencyDispenser twentyDispenser = new TwentyDispenser();
protected static PaperCurrencyDispenser tenDispenser = new TenDispenser();
protected static PaperCurrencyDispenser dispenserChain;
static {
// construct the chain of the currency dispensers in higher to lower
// denomination
hundredDispenser.setNextDispenser(fiftyDispenser);
fiftyDispenser.setNextDispenser(twentyDispenser);
twentyDispenser.setNextDispenser(tenDispenser);
dispenserChain = hundredDispenser;
}
public static void withdraw(PaperCurrency currency) {
if (currency != null) {
dispenserChain.dispense(currency);
}
}
}
Now its time to write our Main class to execute and test the output:
xxxxxxxxxx
package org.trishinfotech.responsibility;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
try (Scanner scanner = new Scanner(System.in)) {
do {
System.out.println(
"Please enter amount to withdraw (multiple of 10, max 1000$, Press Ctrl + C to end): ");
int amount = scanner.nextInt();
if (isValid(amount)) {
ATMWithdrawal.withdraw(new PaperCurrency(amount));
}
} while (true);
}
}
private static boolean isValid(int amount) {
if (amount <= 0) {
System.out.println("Invalid amount. Try again!");
return false;
} else if (amount > 1000) {
System.out.println("Daily withdrawal limit is 1000$. Try again!");
return false;
} else if (amount % 10 != 0) {
System.out.println("Amount must be mutiple of 10s, Try again!");
return false;
}
return true;
}
}
Below is the output of the program:
xxxxxxxxxx
Please enter amount to withdraw (multiple of 10, max 1000$, Press Ctrl + C to end):
150
Dispensing '1' 100$ currency note.
Dispensing '1' 50$ currency note.
Please enter amount to withdraw (multiple of 10, max 1000$, Press Ctrl + C to end):
20
Dispensing '1' 20$ currency note.
Please enter amount to withdraw (multiple of 10, max 1000$, Press Ctrl + C to end):
10
Dispensing '1' 10$ currency note.
Please enter amount to withdraw (multiple of 10, max 1000$, Press Ctrl + C to end):
110
Dispensing '1' 100$ currency note.
Dispensing '1' 10$ currency note.
Please enter amount to withdraw (multiple of 10, max 1000$, Press Ctrl + C to end):
250
Dispensing '2' 100$ currency note.
Dispensing '1' 50$ currency note.
Please enter amount to withdraw (multiple of 10, max 1000$, Press Ctrl + C to end):
220
Dispensing '2' 100$ currency note.
Dispensing '1' 20$ currency note.
Please enter amount to withdraw (multiple of 10, max 1000$, Press Ctrl + C to end):
201
Amount must be mutiple of 10s, Try again!
Please enter amount to withdraw (multiple of 10, max 1000$, Press Ctrl + C to end):
210
Dispensing '2' 100$ currency note.
Dispensing '1' 10$ currency note.
Please enter amount to withdraw (multiple of 10, max 1000$, Press Ctrl + C to end):
580
Dispensing '5' 100$ currency note.
Dispensing '1' 50$ currency note.
Dispensing '1' 20$ currency note.
Dispensing '1' 10$ currency note.
Please enter amount to withdraw (multiple of 10, max 1000$, Press Ctrl + C to end):
The Source Code can be found here: Chain-of-Responsibility-Design-Pattern-Sample-Code
The Chain of Responsibility, Command, Mediator and Observer offers various ways of connecting senders and receivers of requests.
- The Chain of Responsibility pattern is used to sequentially pass a request along a dynamic chain of receivers until at least one of them handles it.
- The Command pattern is used to establish unidirectional connection between sender and receiver objects.
- The Mediator pattern is used to eliminate direct coupling between sender and receiver objects and force them to communicate indirectly via a mediator object.
- The Observer pattern allows receivers to dynamically subscribe and unsubscribe for the requests.
I hope this tutorial helps in understanding of the chain of responsibility design pattern.
Liked the article? Please don't forget to press that like button. Happy coding!
This article also conclude my series of articles on basic design patterns. Please comment to tell me how much you like the articles? Based on your response, I will come with more articles on various technologies and languages like C++, Scala, Groovy, Big Data, Database along with Java.
Need more articles, please visit my profile: Brijesh Saxena
Opinions expressed by DZone contributors are their own.
Comments