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.
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!