Loading

责任链设计模式

在现实生活中,一个事件需要经过 多个对象 处理是很常见的场景。比如:采购审批流程、请假流程等。公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同,员工必须根据需要请求的天数去找不同的领导签名,即员工必须记住每个领导的姓名、电话和地址信息,这使得该流程变得复杂冗余。

在计算机软件开发中也有相关的例子,比如 异常处理,处理程序根据异常的类型决定自己是否处理该异常;还有 Struts2拦截器JSPServlet 的 Filter过滤器等,都可以考虑使用 责任链(职责链)设计模式 来实现。Servlet 的 Filter过滤器的实现确实使用了 责任链设计模式

模式的定义与特点

责任链(Chain of Responsibility) 模式的定义:为了避免 请求发送者多个请求处理者 耦合在一起,于是将所有的 请求处理者 通过让 前一对象 记住 其下一个对象的引用 的方式而形成了一个 链条;当有请求发生时,可将请求沿着该 链条 传递,直到有对象处理当前请求为止。

责任链模式 中,客户只需要将请求发送到 责任链 上即可,无需关心请求的 处理 和请求的 传递过程,请求会 自动 进行传递,因此 责任链模式 将请求的 发送者 和请求的 处理者 解耦合了

责任链模式是一种 对象行为型 模式

主要优点

  1. 降低了对象之间的 耦合度。该模式使得一个对象无需知道到底是哪一个对象处理其请求,也无需知道 链条 的结构,发送者和接收者也无需拥有对方的明确信息
  2. 增强了系统的 可扩展性。可以根据需要增加新的 请求处理类,符合 开闭原则
  3. 增强了给对象指派职责的 灵活性。当工作流程发生变化,可以 动态 的改变 链条 内的成员或者调动它们的 次序,也可以 动态 的增加或者删除责任
  4. 简化了对象之间的 连接。每个对象只需持有一个指向其后继者的 引用,不需要持有其它所有处理者的 引用
  5. 责任 分化。每个类只需处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的 责任范围,符合 单一职责原则

主要缺点

  1. 不能保证请求一定会被处理。由于请求没有明确的 接收者,所有不能保证它一定会被处理,该请求可能一直传递到 链条 的末端都得不到处理
  2. 如果 责任链 比较长,请求的处理可能涉及多个处理对象,处理对象过多将会对 系统性能 产生影响
  3. 责任链 建立的 合理性 要靠 客户端 来保证,增加了客户端的 复杂性,可能会由于 责任链 的错误设置而导致 系统出错,如可能造成 循环调用(责任链的实现基于 递归)

模式的结构与实现

模式的结构

  1. 抽象处理者(Handler)角色:定义一个处理请求的 接口 或者 抽象类,包含 抽象处理方法 和一个 后继连接
  2. 具体处理者(Concrete Handler)角色:实现 抽象处理者处理方法,判断能否处理本次请求,如果可以处理则处理,否则将请求转给当前具体处理者的 后继者
  3. 客户类(Client)角色:创建处理链(即创建 具体处理者 对象),并向 链头 的具体处理者提交请求,它不关心 处理细节 和请求的 传递过程

责任链模式 的本质是解耦 请求处理,让请求在 处理链 中能进行 传递被处理;理解 责任链模式 应该理解其 模式,而不是其具体实现。责任链模式 的独到之处是将其节点处理者组合成了 链式结构,并允许节点自身决定是否进行 请求处理转发,相当于让请求 流动 起来

  • 模式结构图

责任链模式结构图

  • 责任链示意图

责任链示意图

模式的实现

  1. 抽象处理者角色-Handler
/**
 * 抽象处理者
 */
public abstract class Handler {
    // 定义后继者引用
    private Handler next;

    public Handler getNext() {
        return next;
    }

    public void setNext(Handler next) {
        this.next = next;
    }

    // 定义处理请求的抽象方法
    public abstract void handleRequest(String request);
}
  1. 具体处理者角色-ConcreteHandler1ConcreteHandler2
/**
 * 具体处理者1
 */
public class ConcreteHandler1 extends Handler{
    @Override
    public void handleRequest(String request) {
        if("one".equals(request)){ // 具体处理者1能够处理当前请求
            // 具体处理者1对当前请求进行处理
            System.out.println("具体处理者1负责处理当前请求,已处理完毕...");
        }else { // 具体处理者1不能处理当前请求
            if(this.getNext() != null){ // 当前具体处理者1存在后继者
                // 将当前请求发送给当前具体处理者1的后继者
                this.getNext().handleRequest(request);
            }else{ // 当前具体处理者1不存在后继者
                // 结束请求,返回
                System.out.println("没有任何处理者处理当前请求,调用结束...");
            }
        }
    }
}
/**
 * 具体处理者2
 */
public class ConcreteHandler2 extends Handler{
    @Override
    public void handleRequest(String request) {
        if("two".equals(request)){ // 具体处理者2能够处理当前请求
            // 具体处理者2对当前请求进行处理
            System.out.println("具体处理者2负责处理当前请求,已处理完毕...");
        }else { // 具体处理者2不能处理当前请求
            if(this.getNext() != null){ // 当前具体处理者2存在后继者
                // 将当前请求发送给当前具体处理者2的后继者
                this.getNext().handleRequest(request);
            }else{ // 当前具体处理者2不存在后继者
                // 结束请求,返回
                System.out.println("没有任何处理者处理当前请求,调用结束...");
            }
        }
    }
}
  1. 客户端角色-Client
/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        // 创建具体处理者对象,组装责任链
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        // 设置 handler1(第一个具体处理者对象) 的后继者为 handler2
        handler1.setNext(handler2);
        // 提交请求
        handler1.handleRequest("two");
    }
}
  • 程序运行结果:
具体处理者2负责处理当前请求,已处理完毕...

模式的应用场景

  1. 多个对象 可以处理 同一个请求,但具体由那个对象处理该请求在 运行时 自动确定
  2. 动态 指定一组对象处理请求,或添加新的处理者
  3. 需要在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求

模式的扩展

  • 纯的 责任链模式:一个请求必须被某一个处理者对象所接收,且一个 具体处理者 对某个请求的处理只能采用 自己处理 或者 交给后继者处理 两种方式之一
  • 不纯的 责任链模式:允许出现某一个 具体处理者 对象在承担了请求的 一部分责任 之后,又将 剩余的责任 传递给 后继者,且一个请求可以最终不被任何 接收端对象 所接收(Filter过滤器属于 不纯 的责任链模式)

文章转载于:http://c.biancheng.net/view/1383.html

posted @ 2022-07-08 23:20  赵妹儿  阅读(71)  评论(0编辑  收藏  举报