1.什么是责任链模式?
责任链模式(Chain of Responsibility Pattern):责任链模式就是将请求的接收者对象连成一条链,然后在这一条链上传递请求,直到有个一接收者处理这个请求。通过这样一种方式,避免了请求者和接收者之间的耦合。
说人话: 举个例子,小张来到政府办事大厅办营业执照,可以把小张办营业执照理解为一条请求,政府的办事人员理解为请求的处理者.
由于近年来政府办事效率的提升,小张只需要发起办理执照这条请求,接下来由前台柜员去处理,处理的过程中柜员发现自己不能直接通过,还要上级审核,于是他把请求呈递给他的上司,他的上司看完后觉得自己不能做决定,还需要消防人员去实地检验,最终消防人员验收觉得没问题,于是就把营业执照颁给了小张.
在上述过程中其实小张仅仅只需要发出请求,至于请求是如何被处理的他并不需要关心,这就大大降低了请求者和接受者之间的耦合,请求的处理类似一条链,请求在这条链上传递,最终总有一个人能够处理这条请求,我们称之为责任链模式,这种设计模式在tomcat的filter,mybatis里都有涉及,在文末我会有介绍,接下来先拿最简单的例子入手,毕竟重在理解.
2.为什么要使用责任链模式?
因为可以让你的代码变得逼格满满啊,错了,其实最重要还是:
①将请求者和接收者解耦,各模块功能界限清晰,互不影响.
②更好的可扩展性和灵活性,增加新的接收者变得非常容易.
③简化了对象,使对象不需要清楚链的结构,提高了代码的可读性,便于代码的维护.
3.适用场景
①有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定
②在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
③可动态指定一组对象处理请求
4.实现
这里我拿一个大家比较熟悉的例子来写demo,java有很多日志框架,并且几乎都是支持配置的,你启动的日志优先级不同,显示的日志信息也不同,下面我们就来模拟一下,分别启动debug,info,error级别的日志,在控制台看日志,正常的话应该是debug级别显示的日志最为详细,error显示的日志信息最少.
对于日志的处理,请求实际上只是告诉接收者我当前使用那种级别的日志,至于这个日志最终由那个类来处理,它并不需要关心,请求会沿着这条责任链传递,直到找到能够处理它的类为止.
在正式写代码之前,我觉得有必要梳理下责任链模式的结构,先看下面三张图,分别是tomcat的filter,mybatis的plugin,基于责任链模式实现的handler,有没有发现实际上是千篇一律的,责任链模式主要就是由请求的发起者和处理者构成,处理者一般是多个,构成一条链.
图1
图2
图3
弄清了结构之后,下面就动手开发一套沙雕版的日志框架…
这套日志框架里,有一个抽象的爸爸Logger,他有三个儿子,以后可能会生出更多个…不影响我们写代码.三个儿子分别是InfoLog,ErroLog,DebugLog,他们都继承了爸爸Logger,ResponsibilityPatternTest模拟请求的发起者.
代码比较简单,爸爸Logger存放了优先级和责任链中的下一个元素:
public abstract class Logger {
public static int DEBUG = 1;
public static int INFO = 2;
public static int ERROR = 3;
protected int level;
protected Logger nextLogger;
public void setNextLogger(Logger nextLogger) {
this.nextLogger = nextLogger;
}
protected abstract void write(String msg);
public void logMessage(int level, String msg) {
if (this.level >= level) {
write(msg);
}
if (nextLogger != null) {
nextLogger.logMessage(level, msg);
}
}
}
儿子们分别实现了父类中的抽象方法write(),并在构造器中指定了优先级的参数:
public class DebugLog extends Logger {
public DebugLog(int level) {
super.level = level;
}
@Override
protected void write(String msg) {
System.out.println("=========>DebugLog:" + msg);
}
}
public class InfoLog extends Logger {
public InfoLog(int level) {
super.level = level;
}
@Override
protected void write(String msg) {
System.out.println("=========>InfoLog:" + msg);
}
}
public class ErrorLog extends Logger {
public ErrorLog(int level) {
super.level = level;
}
@Override
protected void write(String msg) {
System.out.println("=========>ErrorLog:" + msg);
}
}
测试类里分别创建了这三个儿子,并制定了儿子们的下一个元素:
/**
* 责任链模式测试类
*/
public class ResponsiblityPatternTest {
private static Logger getLogger(){
Logger infoLog = new InfoLog(Logger.INFO);
Logger debugLog = new DebugLog(Logger.DEBUG);
Logger errorLog = new ErrorLog(Logger.ERROR);
debugLog.setNextLogger(infoLog);
infoLog.setNextLogger(errorLog);
return debugLog;
}
public static void main(String[] args) {
Logger logger = getLogger();
logger.logMessage(Logger.DEBUG,"这是debug级别的log");
System.out.println("------------------------------------");
logger.logMessage(Logger.INFO,"这是info级别的log");
System.out.println("------------------------------------");
logger.logMessage(Logger.ERROR,"这是error级别的log");
}
}
在main方法中分别调用debug,info,error级别的日志,测试结果如下:
完全符合预期,不同级别的日志请求都找到了它们对应的类去处理.
5.结语
忙里抽闲再度学习和复习了一波设计模式,本篇也是分享的十篇设计模式中的最后一篇,23种设计模式仅仅介绍了10篇,尚有13种未
介绍.
通过这几年做程序员的学习和体验,设计模式确实是Java程序员必备的一项技能,掌握一些常见的设计模式,可以让代码质量有质的
飞跃,其实对大部分程序员来说,能够熟练掌握6种左右设计模式,了解10种以上设计模式即可应付日常开发和基本的代码质量要求,
能完全熟练掌握23种设计模式的,那不是人,是神! 因为有很多设计模式在实际开发中不常用,时间久了也就生疏甚至忘了,所以真正
熟练掌握那么多设计模式对大部分程序员来说还是不够现实的.
掌握这些设计模式,对阅读Jdk源码和一些优秀的开源框架也比较有帮助,否则你可能很难理解代码为什么要写成那样,知其优秀而不
知其所以优秀,总之一言难尽,学海无涯啊,继续搬砖学习…