22种设计模式——责任链模式

1. 概念

责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。
在这里插入图片描述
这种模式是一种很容易理解,且很实用的模式。话不多说,从问题引入:假如你正在开发一个在线订购系统。 你希望对系统访问进行限制, 只允许认证用户创建订单。 此外, 拥有管理权限的用户也拥有所有订单的完全访问权限。

简单规划后, 你会意识到这些检查必须依次进行。 只要接收到包含用户凭据的请求, 应用程序就可尝试对进入系统的用户进行认证。 但如果由于用户凭据不正确而导致认证失败, 那就没有必要进行后续检查了。
在这里插入图片描述
在接下来的几个月里, 你实现了后续的几个检查步骤。

  • 一位同事认为直接将原始数据传递给订购系统存在安全隐患。 因此你新增了额外的验证步骤来清理请求中的数据。

  • 过了一段时间, 有人注意到系统无法抵御暴力密码破解方式的攻击。 为了防范这种情况, 你立刻添加了一个检查步骤来过滤来自同一 IP 地址的重复错误请求。

  • 又有人提议你可以对包含同样数据的重复请求返回缓存中的结果, 从而提高系统响应速度。 因此, 你新增了一个检查步骤, 确保只有没有满足条件的缓存结果时请求才能通过并被发送给系统。

在这里插入图片描述
检查代码本来就已经混乱不堪, 而每次新增功能都会使其更加臃肿。 修改某个检查步骤有时会影响其他的检查步骤。 最糟糕的是, 当你希望复用这些检查步骤来保护其他系统组件时, 你只能复制部分代码, 因为这些组件只需部分而非全部的检查步骤。

系统会变得让人非常费解, 而且其维护成本也会激增。 你在艰难地和这些代码共处一段时间后, 有一天终于决定对整个系统进行重构。你会怎么做呢?使用责任链模式!!!

责任链模式怎么做呢?责任链会将特定行为转换为被称作处理者的独立对象。 在上述示例中, 每个检查步骤都可被抽取为仅有单个方法的类, 并执行检查操作。 请求及其数据则会被作为参数传递给该方法。

链上的每个处理者都有一个成员变量来保存对于下一处理者的引用,就像一条链表。 除了处理请求外, 处理者还负责沿着链传递请求。 请求会在链上移动, 直至所有处理者都有机会对其进行处理。最重要的是: 处理者可以决定不再沿着链传递请求, 这可高效地取消所有后续处理步骤。

在我们的订购系统示例中, 处理者会在进行请求处理工作后决定是否继续沿着链传递请求。 如果请求中包含正确的数据, 所有处理者都将执行自己的主要行为, 无论该行为是身份验证还是数据缓存。

在这里插入图片描述
简单来说,就是把原来的每层判断变成一个必要的过程,这样虽然会使整个过程多了一些不必要的步骤,但是好处也很明显,代码逻辑清晰,易于维护和扩展,每个模块只需专注自己的功能,图如下,第一个是不使用责任链,第二个是使用责任链:
在这里插入图片描述
在这里插入图片描述
不过还有一种稍微不同的方式 (也是更经典一种), 那就是处理者接收到请求后自行决定是否能够对其进行处理。 如果自己能够处理, 处理者就不再继续传递请求。 因此在这种情况下, 每个请求要么最多有一个处理者对其进行处理, 要么没有任何处理者对其进行处理。 在处理图形用户界面元素栈中的事件时, 这种方式非常常见。

例如, 当用户点击按钮时, 按钮产生的事件将沿着 GUI 元素链进行传递, 最开始是按钮的容器 (如窗体或面板), 直至应用程序主窗口。 链上第一个能处理该事件的元素会对其进行处理。 此外, 该例还有另一个值得我们关注的地方: 它表明我们总能从对象树中抽取出链来。

在这里插入图片描述

  • 总结
    1. 责任链模式常用于解决有多种处理情况的代码,用于简化逻辑,比如我们代码中常常出现的多重if-else判断。
    2. 责任链模式的思想就是把所有处理操作抽离出来成为多个处理者,这多个处理者构成一条链,要处理的数据就在这条链上传递,数据经过整条链的处理或者在某一环节就被处理完毕。

2. 特点

  • 优点
    1. 你可以控制请求处理的顺序。
    2. 单一职责原则。 你可对发起操作和执行操作的类进行解耦。
    3. 开闭原则。 你可以在不更改现有代码的情况下在程序中新增处理者。
  • 缺点:部分请求可能未被处理
  • 使用场景
    1. 当程序需要使用不同方式处理不同种类请求, 而且请求类型和顺序预先未知时, 可以使用责任链模式。该模式能将多个处理者连接成一条链。 接收到请求后, 它会 “询问” 每个处理者是否能够对其进行处理。 这样所有处理者都有机会来处理请求。

    2. 当必须按顺序执行多个处理者时, 可以使用该模式。无论你以何种顺序将处理者连接成一条链, 所有请求都会严格按照顺序通过链上的处理者。

    3. 如果所需处理者及其顺序必须在运行时进行改变, 可以使用责任链模式。如果在处理者类中有对引用成员变量的设定方法, 你将能动态地插入和移除处理者, 或者改变其顺序。


3. 实现

  • UML类图
    在这里插入图片描述
  • Java代码
    1. 处理者抽象类
      /**
       * @Author: chy
       * @Description: 处理者顶层抽象类
       * @Date: Create in 22:58 2021/3/22
       */
      public abstract class Handler {
          /**
           * 指向下一环节的处理者
           */
          protected Handler next;
      
          public void setNext(Handler next) {
              this.next = next;
          }
      
          protected abstract void progress(int request);
      }
      
    2. 具体处理者
      /**
       * @Author: chy
       * @Description: 具体处理者,处理小于0的值
       * @Date: Create in 22:59 2021/3/22
       */
      public class A extends Handler{
      
          @Override
          protected void progress(int request) {
              if (request < 0){
                  System.out.println("A的处理");
              }
              else{
                  this.next.progress(request);
              }
          }
      }
      
      /**
       * @Author: chy
       * @Description: 具体处理者,处理0~5的值
       * @Date: Create in 23:02 2021/3/22
       */
      public class B extends Handler{
      
          @Override
          protected void progress(int request) {
              if (request < 5){
                  System.out.println("B的处理");
              }
              else{
                  this.next.progress(request);
              }
          }
      }
      
      /**
       * @Author: chy
       * @Description: 具体处理者,处理小于5~10的值
       * @Date: Create in 23:02 2021/3/22
       */
      public class C extends Handler{
      
          @Override
          protected void progress(int request) {
              if (request < 10){
                  System.out.println("C的处理");
              }
              else{
                  this.next.progress(request);
              }
          }
      }
      
    3. 客户端
      /**
       * @Author: chy
       * @Description: 客户端
       * @Date: Create in 22:54 2021/3/22
       */
      public class Client {
          public static void main(String[] args) {
              // 指定处理逻辑,这里也可以设置死
              A a = new A();
              B b = new B();
              C c = new C();
              // 设置成环
              a.setNext(b);
              b.setNext(c);
              c.setNext(a);
              // 处理数据
              a.progress(-1);
              a.progress(2);
              a.progress(7);
              // 因为是环,所以也会被前面的处理者处理
              c.progress(-1);
              c.progress(2);
              c.progress(7);
          }
      }
      
    4. 结果
      在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值