目录
1、责任链模式的概念
1.1、百度百科对责任链的定义
1.2、责任链模式
2、责任链模式的作用
3、实现
3.1、责任链模式的通用类图,如下图 1-1:
3.2、代码实现案例
4、责任链的优缺点
4.1、优点
4.2、缺点
5、责任链模式的应用场景
6、结语
前言
这一章节主要介绍行为型模式。
上一章节,我们介绍的是创建型模式,主要关注对象的创建,而这一章节的行为型模式主要关注对象交互、通信和控制流。
大多数行为型模式都基于组合和委托而不是继承。
接下来我们将在这一章节中讲解以下行为型模式:
责任链模式
命令模式
解释器模式
迭代器模式
观察者模式
中介者模式
备忘录模式
状态模式
策略模式
模板方法模式
空对象模式
访问者模式
1、责任链模式的概念
1.1、百度百科对责任链的定义
责任链模式是一种设计模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
1.2、责任链模式
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。
计算机软件是用来处理信息的,有多种不同的方式来组织和处理信息。之前我们提过设计模式需要遵循的原则,在面向对象编程中,我们应该赋予一个类单一职责,从而使得类容易维护和扩展。
设想一个场景,需要对一批从客户端来的数据进行多种不同的操作,我们会使用多个不同的类负责不同的操作,而不是使用一个类集成所有的操作,这样做能让代码松耦合且简洁。
这些类被称为处理器,第一个处理器会接收请求,如果它需要执行操作则会进行一次调用,如果不需要则会传递给第二个处理器。类似地,第二个处理器确认并将请求传递给责任链中下一个处理器。
2、责任链模式的作用
目的:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,如果链上当前处理器可以处理,就处理,不能处理,就把请求传递给下一个处理器,就这样直到有对象处理它为止。
主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
3、实现
3.1、责任链模式的通用类图,如下图 1-1:
图 1-1
图1-1中包含以下三个类:
Client(客户端):客户端是使用责任链模式的应用程序的主要结构。它的职责是实例化一个处理器的链,然后在第一个对象中调用 handleRequest 方法。
Handler(处理器):这是一个抽象类,提供给所有实际处理器进行继承。它拥有一个 HandleRequest 方法,用来接收需要处理的请求。
ConcreteHandler(具体处理器):这是一个实现了 handleRequest 方法的具体类。每一个具体处理器都维持一个引用,指向链中下一个具体处理器,需要检查它自身是否能处理这个请求,如果不能处理就会把请求传递给链中的下一个具体处理器。
3.2、代码实现案例
我们创建抽象类 AbstractLogger,带有详细的日志记录级别。然后我们创建三种类型的记录器,都扩展了 AbstractLogger。每个记录器消息的级别是否属于自己的级别,如果是则相应地打印出来,否则将不打印并把消息传给下一个记录器。
先来看一张日志记录的类图结构,如图1-2:
图1-2
1)先来创建一个抽象处理器类 AbstaractLogger
AbstractLogger.java
package com.zhaoyanfei.designpattern.chainOfResponsibilityPattern;
/**
*
* @Date 2022年10月5日
* @author zhaoYanFei
*
*/
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;
public void setNextLogger(AbstractLogger nextLogger){
this.nextLogger = nextLogger;
}
public void logMessage(int level, String message){
if(this.level <= level){
write(message);
}
if(nextLogger !=null){
nextLogger.logMessage(level, message);
}
}
abstract protected void write(String message);
}
这个基类中我们有设置下一个责任处理器的方法 setNextLogger 方法。
2)创建一个继承了基类的 对象处理器 ConsoleLogger
ConsoleLogger .java
package com.zhaoyanfei.designpattern.chainOfResponsibilityPattern;
public class ConsoleLogger extends AbstractLogger {
public ConsoleLogger(int level){
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("Standard Console::Logger: " + message);
}
}
3)类似的再创建继承了基类 AbstractLogger 的两个处理器,FileLogger 和 ErrorLogger
FileLogger.java
package com.zhaoyanfei.designpattern.chainOfResponsibilityPattern;
public class FileLogger extends AbstractLogger {
public FileLogger(int level){
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("File::Logger: " + message);
}
}
ErrorLogger.java
package com.zhaoyanfei.designpattern.chainOfResponsibilityPattern;
public class ErrorLogger extends AbstractLogger {
public ErrorLogger(int level){
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("Error Console::Logger: " + message);
}
}
4)客户端构建一个处理器的责任链请求示例 ChainPatternDemo。
创建不同类型的记录器,赋予它们不同的错误级别;
并在每个记录器中设置下一个记录器,每个记录器中的下一个记录器代表的是链的一部分。
ChainPatternDemo.java
package com.zhaoyanfei.designpattern.chainOfResponsibilityPattern;
/**
* 客户端构建一个处理器的责任链
* @Date 2022年10月5日
* @author zhaoYanFei
*
*/
public class ChainPatternDemo {
private static AbstractLogger getChainOfLoggers() {
//先实例化不同级别的日志对象
AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);
//error 级别最高,初始error日志处理器处理,如果不能处理,丢给下一个处理器
errorLogger.setNextLogger(fileLogger);
//以此类推,上一个FileLogger 不能处理的传递给ConsoleLogger对象处理
fileLogger.setNextLogger(consoleLogger);
return errorLogger;
}
public static void main(String[] args) {
//构建责任链
AbstractLogger chainOfLoggers = getChainOfLoggers();
chainOfLoggers.logMessage(AbstractLogger.INFO, "This is an info information.");
chainOfLoggers.logMessage(AbstractLogger.DEBUG, "This is an debug information.");
chainOfLoggers.logMessage(AbstractLogger.ERROR, "This is an error information.");
}
}
5)查看运行结果
# 4、责任链的优缺点
## 4.1、优点
1、降低耦合度。它将请求的发送者和接收者解耦。
2、简化了对象。使得对象不需要知道链的结构。
3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
4、增加新的请求处理类很方便。
## 4.2、缺点
1、不能保证请求一定被接收。
2、系统性能将受到一定影响,而且可能会造成循环调用。
3、运行期特征不易观察,排除问题不太友好。
# 5、责任链模式的应用场景
1、事件处理器,例如 js 中的事件冒泡;大部分图形用户界面框架使用责任链模式来处理事件。
2、日志处理器
3、JAVA WEB 中 servlet ,在 Java 中,javax.servlet.Filter 被用来过滤请求或者响应。 doFilter 方法把过滤器链作为一个参数接收,它能够传递请求。
4、JAVA WEB 中 Apache Tomcat 对 Encoding 的处理,Struts2 的拦截器等等。
# 6、结语