Close
Deception of logging levels of logger system
Logging system

Chain of Responsibility pattern

Introduction

Chain of responsibility pattern states that each behaviour is to be extracted in its own class. This class are called handlers, furthermore these handlers are chained together in link. So that when the actual request comes in, this request travels the chain of handlers up until there is any handler that handles the request.

Where do we need chain of responsibility?

This pattern can be used in cases when there are different types of requests to be handled and the order of these requests are unknown.

Like for instance lets say different levels of seniority in the department can approve longer leave. Like the lead can approve only one day, the manager can approve a week and HR can approve for longer. In such senario the request i. e. the number of leaves and order  from the employee is unknown. 

Chain of responsibility internals

This pattern needs two components as follow

  • A common interface which contains a single method that each handler implements.
  • Concrete implements of handlers which contains the processing logic.

Logger system requirements

  • This logger system handles different types of log levels.
  • Logging levels supported are INFO, DEBUG, VERBOSE.
  • Logger system mimics the syslog message logging.
Chain of responsibility class diagram  for logger system

Logger system implementation in java

main.java

working.example.tech.DesignPattern.Behavioural.ChainOfResponsibility.*;
public class Main {
    public static void main(String[] args) {
    	LoggerLibraryClient client = new LoggerLibraryClient();
    	client.RunTest();
    }
}

LoggerInterface.java

package working.example.tech.DesignPattern.Behavioural.ChainOfResponsibility;
public interface LoggerInterface {
    void logMessage(LogType type, String msg);
}

Logger.java

package working.example.tech.DesignPattern.Behavioural.ChainOfResponsibility;
public class Logger {
	final static Logger inst = new Logger();
	LoggerInterface handler;
	public static Logger getLogger() {
		return inst;
	}
	
	Logger() {
		VerboseLogger vLogger = new VerboseLogger(null);
		InfoLogger iLogger = new InfoLogger(vLogger);
		handler = new DebugLogger(iLogger);
	}
	
	public void LogMessage(LogType type, String msg) {
		handler.logMessage(type, msg);
	}
}

VerboseLogger.java

package working.example.tech.DesignPattern.Behavioural.ChainOfResponsibility;
public class VerboseLogger implements LoggerInterface {
    final LogType type = LogType.LOG_TYPE_VERBOSE;
    LoggerInterface nextHandler;
    VerboseLogger(LoggerInterface handler) {
    	nextHandler = handler;
    	
    }
    
	@Override
	public void logMessage(LogType type, String msg) {
		// TODO Auto-generated method stub
		if (type == this.type) {
			System.out.println("Logging: " + type.toString() + " msg: " + msg);
		} else if (nextHandler != null) {
			nextHandler.logMessage(type, msg);
		}
	}
}

DebugLogger.java

package working.example.tech.DesignPattern.Behavioural.ChainOfResponsibility;
public class DebugLogger implements LoggerInterface {
    final LogType type = LogType.LOG_TYPE_DEBUG;
    LoggerInterface nextHandler;
    DebugLogger(LoggerInterface handler) {
    	nextHandler = handler;	
    }
    
	@Override
	public void logMessage(LogType type, String msg) {
		// TODO Auto-generated method stub
		if (type == this.type) {
			System.out.println("Logging: " + type.toString() + " msg: " + msg);
		} else if (nextHandler != null) {
			nextHandler.logMessage(type, msg);
		}
	}
}

InfoLogger.java

package working.example.tech.DesignPattern.Behavioural.ChainOfResponsibility;
public class InfoLogger implements LoggerInterface {
    final LogType type = LogType.LOG_TYPE_INFO;
    LoggerInterface nextHandler;
    InfoLogger(LoggerInterface handler) {
    	nextHandler = handler;
    }
    
	@Override
	public void logMessage(LogType type, String msg) {
		// TODO Auto-generated method stub
		if (type == this.type) {
			System.out.println("Logging: " + type.toString() + " msg: " + msg);
		} else if (nextHandler != null) {
			nextHandler.logMessage(type, msg);
		}
	}
}

LogType.java

package working.example.tech.DesignPattern.Behavioural.ChainOfResponsibility;
public enum LogType {
	LOG_TYPE_INFO,
	LOG_TYPE_DEBUG,
	LOG_TYPE_VERBOSE
}

LoggerLibraryClient.java

package working.example.tech.DesignPattern.Behavioural.ChainOfResponsibility;
public class LoggerLibraryClient implements working.example.tech.interfaces.TestCaseRunner {
	public void logSomething(Logger inst) {
		inst.LogMessage(LogType.LOG_TYPE_DEBUG, "This is debug Message");
	    inst.LogMessage(LogType.LOG_TYPE_VERBOSE, "This is Verbose Message");
	    inst.LogMessage(LogType.LOG_TYPE_INFO, "This is info Message");
	}
	@Override
	public void RunTest() {
		Logger inst = Logger.getLogger();
	    logSomething(inst);   
	}
	@Override
	public void showOut() {
		// TODO Auto-generated method stub
		
	}
}

Output

Logging: LOG_TYPE_DEBUG msg: This is debug Message
Logging: LOG_TYPE_VERBOSE msg: This is Verbose Message
Logging: LOG_TYPE_INFO msg: This is info Message

Conclusion

In this blog we discussed chain of responsibility design pattern in detail with an example of logging system. Hope this helps and you will be able to apply this in any of your upcoming features. We have a lot more design patterns to cover so, stay tuned as more blogs coming up!

More blogs