【设计模式】责任链模式(Chain Pattern)

责任链模式是一种设计模式,通过将多个处理者串联成链,请求在链上传递,直到被合适的处理者处理。例如,商场火灾事件的上报过程就体现了这种模式,从区长到市长,再到州长,最后到总统,每个角色根据其权力决定是否处理请求。此模式降低了对象间的耦合,使得请求处理顺序灵活且可动态调整。在实际应用中,如JS的DOM事件冒泡、Servlet的Filter和Spring的Interceptor都是责任链模式的例子。
摘要由CSDN通过智能技术生成

在这里插入图片描述

 

🔥 核心

责任链上的每个处理者都拥有下一个处理者的引用。

请求被放到责任链上,如果当前处理者无法处理该请求,那么它会把请求传送给下一个处理者,以此类推。

 

🙁 问题场景

一家大型商场发生了火灾。

幸运的是,火灾发生在深夜,所以没有人受伤;但货架上可怜的商品就没这么幸运了,它们都被烧毁,损失达到了一亿美元。市民们上街游行,谴责政府对商场的安全问题监督不善。

办公室里的官员们焦头烂额,不知道该如何处理这件事情…

 

🙂 解决方案

好在,政府有一个完整的上报制度。这是一个链状的结构。

区长 最先得知了事故的发生,他惊慌失措,完全没有遇到过这么大的安全事故,于是他将问题上报给了 市长

市长 挂断了电话后,意识到问题的严重性完全超过了自己的职责范围,于是他又拨通了 州长 的电话;

州长 弄明白事故的缘由后,思考片刻,认为这件事情对全国都有警示意义,于是他又给 总统 发送了电报。

总统 接受到电报后,立即召开紧急会议,并给出了一套完整的解决方案。

最终,商场火灾事件得到了妥善的处理。

你会发现,在整个事件处理过程中,市民与官员、甚至官员之间并没有过多的耦合,市民只需要将请求放到责任链上即可,请求会自动进行传递,直至被处理———这就是责任链模式的魅力。

 

🌈 有趣的例子

如果你对国家层面的追责制度并不了解,那我们就举个身边的例子——学校里的 助理(Aid)主任(Dean)校长(Master) 如何 处理(handle()) 学校里的各个事件。

核心的原则是,如果某个职位的 权力(power) 大于等于事件的 等级(level) ,就在当前职位处理这个事件;否则交给上级处理。

在这里插入图片描述

 领导(抽象类)
abstract class Leader {
    // 权力
    protected int power;
    // 下一个处理者
    private Leader nextLeader;

    public void setNextLeader(Leader leader) {
        nextLeader = leader;
    }

    public Leader getNextLeader() {
        return nextLeader;
    }

    public void handle(int level) {
        if (power >= level) {
            System.out.println("我已经处理了这件事情(^_^)");
        } else if (this.getNextLeader() != null) {
            System.out.println("我处理不了这件事情,但我把它汇报给了上级(>_<)");
            this.getNextLeader().handle(level);
        } else {
            System.out.println("这件事情没有得到解决(#_#)");
        }
    }
}


 助理
class Aid extends Leader {
    public Aid() {
        this.power = 2;
    }

    @Override
    public void handle(int level) {
        System.out.println("我是助理");
        super.handle(level);
    }
}

 主任
class Dean extends Leader {
    public Dean() {
        this.power = 6;
    }

    @Override
    public void handle(int level) {
        System.out.println("我是主任");
        super.handle(level);
    }
}

 校长
class Master extends Leader {
    public Master() {
        this.power = 10;
    }

    @Override
    public void handle(int level) {
        System.out.println("我是校长");
        super.handle(level);
    }
}
public class ChainPatternDemo {
    public static void main(String[] args) {

        // 生成几个领导对象
        Leader aid = new Aid();
        Leader dean = new Dean();
        Leader master = new Master();

        // 组成责任链
        aid.setNextLeader(dean);
        dean.setNextLeader(master);

        // 请求放到责任链上
        aid.handle(9);
    }
}
我是助理
我处理不了这件事情,但我把它汇报给了上级(>_<)
我是主任
我处理不了这件事情,但我把它汇报给了上级(>_<)
我是校长
我已经处理了这件事情(^_^

 

☘️ 使用场景

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

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

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

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

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

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

 

🧊 实现方式

(1)声明处理者接口并描述请求处理方法的签名。

  • 确定客户端如何将请求数据传递给方法。最灵活的方式是将请求转换为对象,然后将其以参数的形式传递给处理函数。

(2)为了在具体处理者中消除重复的样本代码,你可以根据处理者接口创建抽象处理者基类。

  • 该类需要有一个成员变量来存储指向链上下个处理者的引用。你可以将其设置为不可变类。但如果你打算在运行时对链进行改变,则需要定义一个设定方法来修改引用成员变量的值。
  • 为了使用方便,你还可以实现处理方法的默认行为。如果还有剩余对象,该方法会将请求传递给下个对象。 具体处理者还能够通过调用父对象的方法来使用这一行为。

(3)依次创建具体处理者子类并实现其处理方法。每个处理者在接收到请求后都必须做出两个决定:

  • 是否自行处理这个请求。
  • 是否将该请求沿着链进行传递。

(4)客户端可以自行组装链,或者从其他对象处获得预先组装好的链。在后一种情况下,你必须实现工厂类以根据配置或环境设置来创建链。

(5)客户端可以触发链中的任意处理者,而不仅仅是第一个。请求将通过链进行传递,直至某个处理者拒绝继续传递,或者请求到达链尾。

(6)由于链的动态性,客户端需要准备好处理以下情况:

  • 链中可能只有单个链接。
  • 部分请求可能无法到达链尾。
  • 其他请求可能直到链尾都未被处理。

 

🎲 优缺点

  ➕ 你可以控制请求处理的顺序。

  ➕ 降低耦合度,它将请求的发送者和接收者解耦。

  ➕ 简化了对象,使得对象不需要知道链的结构。

  ➕ 单一职责原则。你可对发起操作和执行操作的类进行解耦。

  ➕ 开闭原则。你可以在不更改现有代码的情况下在程序中新增处理者。

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

  ➖ 可能会造成循环调用。

  ➖ 可能不容易观察运行时的特征,有碍于除错。

 

🌸 补充

 你和责任链其实是老朋友了——JS的DOM树冒泡,Servlet的Filter过滤器,Spring中的Interceptor拦截器…

 

🔗 参考网站

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值