责任链模式 - Chain of Responsibility Pattern

WHAT

定义

Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,知道有对象处理它为止。

责任链模式的重点是在“链”上,由一条链去处理相似的请求在链中决定谁来处理这个请求,并返回相应的结果。

类图

Handler类 - 处理者

public abstract class Handler {
  private Handler nextHandler;
  // 每个处理者都必须对请求做出处理
  public final Response handleMessage(Request request){
    Response response = null;
    // 判断是否是自己的处理级别
    if(this.getHandlerLevel().equels(request.getRequestLevel())){
      response = this.echo(request);
    }else {
      // 不属于自己的处理级别
      // 判断是否有下一个处理者
      if(this.nextHandler != null){
				response = this.nextHanlder.handleMessage(request);
      }else{
        // 没有适当的处理者,业务自行处理
      }
    }
    return response;
  }
  
  // 设置下一个处理者是谁
  public void setNext(Handler _handler){
    this.nextHandler = _handler;
  }
  
  // 每个处理者都有一个处理级别
  protected abstract Level getHandlerLevel();
  // 每个处理者都必须实现处理任务
  protected abstract Response echo(Request request);
}

处理者实现了三个职责:

  • 定义一个请求的处理方法handleMessage,唯一对外开放的方法
  • 定义一个链的编排方法setNext,设置下一个处理者
  • 定义了具体的请求者必须实现的两个方法
    • 定义自己能够处理的级别getHandlerLevel
    • 具体的处理任务echo

具体处理者

public class ConcreteHandler1 extends Handler {
  // 定义自己的处理逻辑
  protected Response echo(Request request){
    // 完成处理逻辑
    return null;
  }
  // 设置自己的处理级别
  protected Level getHandlerLevel(){
    // 设置自己的处理界别
    return null;
  }
}

public class ConcreteHandler2 extends Handler{
  // 定义自己的处理逻辑
  protected Response echo(Request request){
    // 完成处理逻辑
		return null;
  }
  // 设置自己的处理级别
  protected Level getHandlerLevel(){
    // 设置自己的处理级别
    return null;
  }
}

public class ConcreteHandler3 extends Handler {
  protected Response echo(Request request){
    return null;
  }
  protected Level getHandlerLevel(){
    return null;
  }
}

其中

  • Level类 - 负责定义请求和处理级别

    public class Level{
      // 定义一个请求和处理级别
    }
    
  • Request类负责封装请求

    public class Request {
      // 请求的等级
      public Level getRequestLevel(){
        return null;
      }
    }
    
  • Response负责封装链中返回的结果

    public class Response {
      /// 处理者返回的数据
    }
    

场景类

在场景类或高层模块中对链进行组装,并传递请求,返回结果

public class Client {
  public static void main(String[] args){
    // 声明所有的处理节点
    Handler handler1 = new ConcreteHandler1();
   	Handler handler2 = new ConcreteHandler2();
    Handler handler3 = new ConcreteHandler3();
    //设置联众的阶段顺序 1 -> 2 -> 3
    handler1.setNext(handler2);
    handler2.setNext(handler3);
    // 提交请求,返回结果
    Resonse response = handler1.handlerMessage(new Request());
  }
}

WHY

优势

将请求和处理分开

请求者可以不用知道是谁处理,是哪个节点处理

处理者不需要知道请求者的全貌,只要根据Request需要的内容传入即可

两者解耦,提高系统的灵活性

劣势

性能问题

每个请求都是从链头开始遍历到链尾,特别在链较长的情况下,性能是一个非常大的问题

调试不方便

在链条较长时,整个环节较多,实现上采用类似递归的方式,调试起来会比较复杂。

HOW

注意事项

链中节点的数量需要控制,避免出现超长链的情况,

一般的做法是:

在Hnadler中设置一个最大节点数量,在setNext方法中判断那是否已经超过其阈值,超过则不允许该链建立,避免无意识地破坏系统性能。

最佳实践

上面的通用源码中的Hanlder是抽象类,融合了模板方法模式,每个实现类都要实现两个方法:echo方法处理请求和getHandlerLevel获取处理界别,做到了单一职责原则和迪米特法则。各个实现类只完成一个动作或逻辑,也就只有一个原因引起类的改变。

TIPS

一般在实际应用中,会有一个 封装类对责任模式进行封装,也就是替代Client类,直接返回链中的第一个处理者,具体链的设置不需要高层次模块关联,简化了高层次模块的调用,减少模块间的耦合,提高系统的灵活性。


《设计模式之禅》第十六章 责任链模式