设计模式:责任链模式

意图

责任链模式(Chain of Responsibility)是一种行为设计模式 允许你将请求沿着处理者链进行发送 收到请求后 每个处理者均可对请求进行处理 或将其传递给链上的下个处理者

责任链模式结构

责任链设计模式的结构

处理者 Handler 声明了所有具体处理者的通用接口 该接口通常仅包含单个方法用于请求处理 但有时其还会包含一个设置链上下个处理者的方法

基础处理者 Base Handler 是一个可选的类 你可以将所有处理者共用的样本代码放置在其中

通常情况下 该类中定义了一个保存对于下个处理者引用的成员变量 客户端可通过将处理者传递给上个处理者的构造函数或设定方法来创建链 该类还可以实现默认的处理行为 确定下个处理者存在后再将请求传递给它

具体处理者 Concrete Handlers 包含处理请求的实际代码 每个处理者接收到请求后 都必须决定是否进行处理 以及是否沿着链传递请求

处理者通常是独立且不可变的 需要通过构造函数一次性地获得所有必要地数据

客户端 Client) 可根据程序逻辑一次性或者动态地生成链。 值得注意的是, 请求可发送给链上的任意一个处理者, 而非必须是第一个处理者。

责任链模式适合应用场景

  • 当程序需要使用不同方式处理不同种类请求 而且请求类型和顺序预先未知时 可以使用责任链模式

该模式能将多个处理者连接成一条链 接收到请求后 它会 询问 每个处理者是否能够对其进行处理 这样所有处理者都有机会来处理请求

  • 当必须按顺序执行多个处理者时 可以使用该模式

无论你以何种顺序将处理者连接成一条链 所有请求都会严格按照顺序通过链上的处理者

  • 如果所需处理者及其顺序必须在运行时进行改变 可以使用责任链模式

如果在处理者类中有对引用成员变量的设定方法 你将能动态地插入和移除处理者 或者改变其顺序

责任链模式优缺点

优点:

  •  你可以控制请求处理的顺序
  •  单一职责原则 你可对发起操作和执行操作的类进行解耦
  •  开闭原则 你可以在不更改现有代码的情况下在程序中新增处理者

缺点:

  • 部分请求可能未被处理。

与其他模式的关系

  • 责任链模式 命令模式 中介者模式观察者模式用于处理请求发送者和接收者之间的不同连接方式

    • 责任链按照顺序将请求动态传递给一系列的潜在接收者 直至其中一名接收者对请求进行处理
    • 命令在发送者和请求者之间建立单向连接
    • 中介者清除了发送者和请求者之间的直接连接 强制它们通过一个中介对象进行间接沟通
    • 观察者允许接收者动态地订阅或取消接收请求
  • 责任链通常和组合模式结合使用 在这种情况下 叶组件接收到请求后 可以将请求沿包含全体父组件的链一直传递至对象树的底部

  • 责任链的管理者可使用命令模式实现 在这种情况下 你可以对由请求代表的同一个上下文对象执行许多不同的操作

    还有另外一种实现方式 那就是请求自身就是一个命令对象 在这种情况下 你可以对由一系列不同上下文连接而成的链执行相同的操作

  • 责任链装饰模式的类结构非常相似 两者都依赖递归组合将需要执行的操作传递给一系列对象 但是 两者有几点重要的不同之处

    责任链的管理者可以相互独立地执行一切操作 还可以随时停止传递请求 另一方面 各种装饰可以在遵循基本接口的情况下扩展对象的行为 此外 装饰无法中断请求的传递

在 Java 中使用模式

使用示例 责任链模式在 Java 程序中并不常见 因为它仅在代码与对象链打交道时才能发挥作用

该模式最流行的使用案例之一是在 GUI 类中将事件向上传递给父组件 另一个值得注意的使用案例是依次访问过滤器

下面是该模式在核心 Java 程序库中的一些示例

示例代码

处理者 Handler 

public interface Logger {
  int INFO = 1;
  int DEBUG = 2;
  int ERROR = 3;

  void logMessage(int level, String message);
}

基础处理者 Base Handler

public abstract class AbstractLogger implements Logger {
  protected int level;

  protected AbstractLogger nextLogger;

  public void setNextLogger(AbstractLogger nextLogger) {
    this.nextLogger = nextLogger;
  }

  @Override
  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);
}

具体处理者 Concrete Handlers) 

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);
  }
}
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);
  }
}
public class FileLogger extends AbstractLogger {
  public FileLogger(int level) {
    this.level = level;
  }

  @Override
  protected void write(String message) {
    System.out.println("File::Logger: " + message);
  }
}

客户端 Client) 

public class Client {

  private static Logger getChainOfLoggers() {
    AbstractLogger errorLogger = new ErrorLogger(Logger.ERROR);
    AbstractLogger fileLogger = new FileLogger(Logger.DEBUG);
    AbstractLogger consoleLogger = new ConsoleLogger(Logger.INFO);

    errorLogger.setNextLogger(fileLogger);
    fileLogger.setNextLogger(consoleLogger);

    return errorLogger;
  }

  public static void main(String[] args) {
    Logger loggerChain = getChainOfLoggers();

    loggerChain.logMessage(Logger.INFO, "This is an information.");

    loggerChain.logMessage(Logger.DEBUG, "This is a debug level information.");

    loggerChain.logMessage(Logger.ERROR, "This is an error information.");
  }
}