userimage

Understanding Chain of responsibility design pattern using java code example

Chain of Responsibility (CoR) is part of behavioral design pattern, where sender sends a request to a chain of objects and the objects from the chain decides themselves by whom the request will be served. Chain of responsibility helps to decouple sender of the request and receiver of the request and helps to achieve complete decoupling between the sender and the receiver. With decoupling sender have no knowledge of the receivers interface which is doing certain operation.

Problems with CoR:

It might fail, Incase a request comes to get solved by CoR and the object which actually can solve the problem might not get chance to solve/serve the request. This happens because of improper chain sequence. A chain sequence may not be suitable for all type of scenarios.

Example of CoR:

If we take Java as programming language and see the internal features, will find servlet filter, Java exception handling mechanism etc. If we see java exception handling is the best example of CoR.

In java we write java exception listed in the catch statement and when there is an exception the catch list get scanned one-by-one from top till it reaches to finally block if it exist. For e.g.



try {
	FileInputStream fileInputStream = new FileInputStream(<the file object with path>);
	BufferedReader br = new BufferedReader(new InputStreamReader(fileInputStream));
	String line = br.readLine().trim();
	int number = Integer.parseInt(line);
	...
} catch (FileNotFoundException f){
	// do something with the exception
} catch (IOException e){
	// do something with the exception
} catch (NumberFormatException n) {
	// do something with the exception
}

If we analys above example we have 3 catch blocks having exceptions like:

1) FileNotFoundException
2) IOException
3) NumberFormatException

And if some case the code throws FileNotFoundException then the request is served and will not go to the step-2 and step-3 Or if the code throws exception like NumberFormatException then the check will come from step-1 which is FileNotFoundException object and FileNotFoundException object is not responsible of handling
NumberFormatException so will move to the step-2 and so on till the right object for the request not found.

UML diagram for CoR:


Implementation using Java:

public abstract class Logger {
	public static int ERROR = 3;
	public static int INFO = 5;
	public static int DEBUG = 7;
	protected int mask;
	
	// The next element in the chain
	protected Logger next;
	
	public Logger setNext(Logger log) {
		next = log;
		return log;
	}
	
	public void message(String msg, int priority) {
		if(priority <= mask){
			writeMessage(msg);
		}
		if(Objects.notNull(next)) {
			next.message(msg, priority);
		}
	}
	
	protected abstract void writeMessage(String msg);
}

public class ConsoleLogger extends Logger {
	public ConsoleLogger(int mask) {
		this.mask = mask;
	}
	
	protected void writeMessage(String msg) {
		System.out.println(msg);
	}
}

public class EmailLogger extends Logger {
	public EmailLogger(int mask) {
		this.mask = mask;
	}
	
	protected void writeMessage(String msg) {
		sendEmail(msg);
	}
	
	...
}

public class ErrorLogger extends Logger {
	public ErrorLogger(int mask) {
		this.mask = mask;
	}
	
	protected void writeMessage(String msg) {
		System.err.println(msg);
	}
}

public class ChainOfResponsibilityMain {
	public static void main(String... args) {
		Logger logger = new ConsoleLogger(Logger.DEBUG);
		Logger logger1 = logger.setNext(new EmailLogger(Logger.INFO));
		Logger logger2 = logger1.setNext(new ErrorLogger(Logger.ERROR));
		logger.message("Entering to DEBUG", Logger.DEBUG);
		logger.message("Entering to INFO", Logger.INFO);
		logger.message("Entering to ERROR", Logger.ERROR);
	}
}


When to use CoR:

1) If requirement is like sernder/client need not to know which object is serving the request.
2) If Objects in the chain know thire responsibility like, who can searve what type of request.
3) If object have reponsibility to forward the request if not capable to searve the request.
4) The chain of objects have capability at runtime to decide which candidate have capablity to handle the request.