使多个对象都有机会处理请求,从而避免请求的发送者与请求处理者耦合在一起。将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
注意:责任链模式也叫职责链模式。
在责任链模式中,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,所以责任链将请求的发送者和请求的处理者解耦了。
我们创建抽象类 AbstractLogger,带有详细的日志记录级别。然后我们创建三种类型的记录器,都扩展了 AbstractLogger。每个记录器消息的级别是否属于自己的级别,如果是则相应地打印出来,否则将不打印并把消息传给下一个记录器。
/** * 抽象的记录器类 */ public abstract class AbstractLogger { public static int INFO = 1; public static int DEBUG = 2; public static int ERROR = 3; protected int level; //责任链中的下一个元素 protected AbstractLogger nextLogger; /** * 设置下一个元素 * * @param nextLogger */ public void setNextLogger(AbstractLogger nextLogger) { this.nextLogger = nextLogger; } /** * 打印日志 * * @param level * @param message */ public void logMessage(int level, String message) { if (this.level <= level) { write(message); } if (nextLogger != null) { nextLogger.logMessage(level, message); } } /** * 打印日志 * * @param message */ abstract protected void write(String message); }
创建扩展了该记录器类的实体类。
/** * 控制台日志 */ public class ConsoleLogger extends AbstractLogger { /** * 构造方法 * @param level */ public ConsoleLogger(int level){ this.level = level; } /** * 打印消息 * @param message */ @Override protected void write(String message) { System.out.println("Standard Console::Logger: " + message); } }
/** * 错误日志 */ public class ErrorLogger extends AbstractLogger { /** * 构造方法 * @param level */ public ErrorLogger(int level){ this.level = level; } /** * 打印日志 * @param message */ @Override protected void write(String message) { System.out.println("Error Console::Logger: " + message); } }
/** * 文件日志 */ public class FileLogger extends AbstractLogger { /** * 构造方法 * @param level */ public FileLogger(int level){ this.level = level; } /** * 打印日志 * @param message */ @Override protected void write(String message) { System.out.println("File::Logger: " + message); } }
创建不同类型的记录器。赋予它们不同的错误级别,并在每个记录器中设置下一个记录器。每个记录器中的下一个记录器代表的是链的一部分。
/** * 责任链模式测试类 */ public class ChainPatternDemo { /** * 获取责任链 * * @return */ private static AbstractLogger getChainOfLoggers() { //构建错误日志 AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR); //构建debug日志 AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG); //构建info日志 AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO); //构建责任链 //设置下一级日志为fileLogger errorLogger.setNextLogger(fileLogger); //设置下一级日志为consoleLogger fileLogger.setNextLogger(consoleLogger); return errorLogger; } public static void main(String[] args) { AbstractLogger loggerChain = getChainOfLoggers(); loggerChain.logMessage(AbstractLogger.INFO, "打印INFO日志"); loggerChain.logMessage(AbstractLogger.DEBUG, "打印DEBUG日志"); loggerChain.logMessage(AbstractLogger.ERROR, "打印ERROR日志"); } }
输出
Standard Console::Logger: 打印INFO日志 File::Logger: 打印DEBUG日志 Standard Console::Logger: 打印DEBUG日志 Error Console::Logger: 打印ERROR日志 File::Logger: 打印ERROR日志 Standard Console::Logger: 打印ERROR日志
request1->request2->response2-response1
public class Servlet_Main { public static void main(String[] args) { Request request = new Request(); request.str = "大家好:),<script>,欢迎访问 xxx.com ,大家都是996 "; Response response = new Response(); response.str = "response"; FilterChain chain = new FilterChain(); chain.add(new HTMLFilter()).add(new SensitiveFilter()); chain.doFilter(request, response); System.out.println(request.str); System.out.println(response.str); } } interface Filter { void doFilter(Request request, Response response, FilterChain chain); } class HTMLFilter implements Filter { @Override public void doFilter(Request request, Response response, FilterChain chain) { request.str = request.str.replaceAll("<", "[").replaceAll(">", "]") + "HTMLFilter()"; chain.doFilter(request, response); response.str += "--HTMLFilter()"; } } class Request { String str; } class Response { String str; } class SensitiveFilter implements Filter { @Override public void doFilter(Request request, Response response, FilterChain chain) { request.str = request.str.replaceAll("996", "955") + " SensitiveFilter()"; chain.doFilter(request, response); response.str += "--SensitiveFilter()"; } } class FilterChain { List<Filter> filters = new ArrayList<>(); int index = 0; public FilterChain add(Filter f) { filters.add(f); return this; } public void doFilter(Request request, Response response) { if(index == filters.size()) return; Filter f = filters.get(index); index ++; f.doFilter(request, response, this); } }
职责链模式可分为纯的职责链模式和不纯的职责链模式两种
一个纯的职责链模式要求一个具体处理者对象只能在两个行为中选择一个:要么承担全部责任,要么将责任推给下家,不允许出现某一个具体处理者对象在承担了一部分或全部责任后又将责任向下传递的情况。而且在纯的职责链模式中,要求一个请求必须被某一个处理者对象所接收,不能出现某个请求未被任何一个处理者对象处理的情况。在前面的请假审批实例中应用的是纯的职责链模式。
在一个不纯的职责链模式中允许某个请求被一个具体处理者部分处理后再向下传递,或者一个具体处理者处理完某请求后其后继处理者可以继续处理该请求,而且一个请求可以最终不被任何处理者对象所接收。Java AWT 1.0中的事件处理模型应用的是不纯的职责链模式,其基本原理如下:由于窗口组件(如按钮、文本框等)一般都位于容器组件中,因此当事件发生在某一个组件上时,先通过组件对象的handleEvent()方法将事件传递给相应的事件处理方法,该事件处理方法将处理此事件,然后决定是否将该事件向上一级容器组件传播;上级容器组件在接到事件之后可以继续处理此事件并决定是否继续向上级容器组件传播,如此反复,直到事件到达顶层容器组件为止;如果一直传到最顶层容器仍没有处理方法,则该事件不予处理。每一级组件在接收到事件时,都可以处理此事件,而不论此事件是否在上一级已得到处理,还存在事件未被处理的情况。显然,这就是不纯的职责链模式,早期的Java AWT事件模型(JDK 1.0及更早)中的这种事件处理机制又叫事件浮升(Event Bubbling)机制。从Java.1.1以后,JDK使用观察者模式代替职责链模式来处理事件。目前,在JavaScript中仍然可以使用这种事件浮升机制来进行事件处理。