设计模式基础概念(行为模式):责任链模式(Chain Of Responsibility)

概述

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

该模式建议你将这些处理者连成一条链。

链上的每个处理者都有一个成员变量来保存对于下一处理者的引用。 除了处理请求外, 处理者还负责沿着链传递请求。 请求会在链上移动, 直至所有处理者都有机会对其进行处理。

  • 处理者可以决定不再沿着链传递请求, 这可高效地取消所有后续处理步骤。

结构

示例

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

  • javax.servlet.Filter#doFilter()
  • java.util.logging.Logger#log()

伪代码实现

Base Handler(基础处理者)

java 复制代码
abstract class BaseHandler {
    // 继任者
    protected Handler successor;
    
    public void setSuccesssor(Handler successor) {this.successor = successor;}
    
    public static Handler link(Handler first, Handler... chain) {
        Handler head = first; // 初始化头部为第一个中间件
        for (Handler nextInChain : chain) {
            head.setSuccesssor(nextInChain); // 将当前中间件的下一个指向链中的下一个中间件
            head = nextInChain; // 移动到链中的下一个中间件
        }
        return first; // 返回链的头部
    }
    
    /**
     * 子类将实现此方法以进行具体的检查。
     *
     * @param params 参数
     * @return 返回检查结果
     */
    public abstract boolean check(Object params);

    /**
     * 在链中的下一个对象上运行检查,或者如果我们在链的最后一个对象中则结束遍历。
     *
     * @param params 参数
     * @return 如果没有下一个中间件,返回 true;否则返回下一个中间件的检查结果
     */
    protected boolean checkNext(Object params) {
        if (next == null) {
            return true; // 如果没有下一个中间件,返回 true
        }
        return next.check(params); // 调用下一个中间件的检查方法
    }
}

Handler(处理者)

Handler(处理者)

处理者1:校验请求次数限制

java 复制代码
public class OneHandler extends BaseHandler {
    private int requestPerMinute;
    private int requestTimes;
    private long currentTime;

    public OneHandler(int requestPerMinute) {
        this.requestPerMinute = requestPerMinute;
        this.currentTime = System.currentTimeMillis();
    }
    
    /**
    * 校验请求次数 一分钟内 是否到达requestPerMinute 达到则停止责任链
    */
    public boolean check(Object params) {
        if (System.currentTimeMillis() > currentTime + 60_000) {
            request = 0;
            currentTime = System.currentTimeMillis();
        }

        request++;
        
        if (request > requestPerMinute) {
            System.out.println("Request limit exceeded!");
            Thread.currentThread().stop();
        }
        return super.checkNext(params);
    }
}

处理者2:

java 复制代码
public class TwoHandler extends BaseHandler {
    
    private Server server;

    public TwoHandler(Server server) {
        this.server= server;
    }
    
    /**
    * 校验其他
    */
    public boolean check(Object params) {
        server.checkOther(params);
        // 其他处理
        return super.checkNext(params);
    }
}

Server(其他辅助service)

定义了handler中的其他处理方法等

java 复制代码
public class Server {
    
    private BaseHandler baseHandler;
    
    public void setMiddleware(BaseHandler baseHandler) {
        this.baseHandler = baseHandler;
    }

    public void checkOther(Object params) {
        // 其他处理逻辑
    }
    
    public boolean test(Object params) {
        if (baseHandler.check(params)) {
            System.out.println("Authorization have been successful!");

            // Do something useful here for authorized users.return true;
        }
        return false;
    }
    
}

Client (客户端)

Client : 需要设置一个职责链的各环节对象串联起来。

java 复制代码
public class ChainOfResponsibilityPattern {
    public static void main(String[] args) {
     BaseHandler handler = Middleware.link(
            new OneHandler(2),
            new TwoHandler(server)
        );
        server.test(params)
    }
}

应用场景

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

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

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

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

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

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

实现方式

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

    • 确定客户端如何将请求数据传递给方法。 最灵活的方式是将请求转换为对象, 然后将其以参数的形式传递给处理函数。
  2. 在具体处理者中消除重复的样本代码, 你可以根据处理者接口创建抽象处理者基类。

    • 该类需要有一个成员变量来存储指向链上下个处理者的引用。 你可以将其设置为不可变类。 但如果你打算在运行时对链进行改变, 则需要定义一个设定方法来修改引用成员变量的值。
    • 为了使用方便, 你还可以实现处理方法的默认行为。 如果还有剩余对象, 该方法会将请求传递给下个对象。 具体处理者还能够通过调用父对象的方法来使用这一行为。
  3. 依次创建具体处理者子类并实现其处理方法。 每个处理者在接收到请求后都必须做出两个决定:

    • 是否自行处理这个请求。
    • 是否将该请求沿着链进行传递。
  4. 客户端可以自行组装链, 或者从其他对象处获得预先组装好的链。 在后一种情况下, 你必须实现工厂类以根据配置或环境设置来创建链。

    • 客户端可以触发链中的任意处理者, 而不仅仅是第一个。 请求将通过链进行传递, 直至某个处理者拒绝继续传递, 或者请求到达链尾。
    • 由于链的动态性, 客户端需要准备好处理以下情况:
      • 链中可能只有单个链接
      • 部分请求可能无法到达链尾
      • 其他请求可能直到链尾都未被处理
相关推荐
转世成为计算机大神3 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
小乖兽技术4 小时前
23种设计模式速记法
设计模式
小白不太白9505 小时前
设计模式之 外观模式
microsoft·设计模式·外观模式
小白不太白9505 小时前
设计模式之 原型模式
设计模式·原型模式
澄澈i5 小时前
设计模式学习[8]---原型模式
学习·设计模式·原型模式
小白不太白95012 小时前
设计模式之建造者模式
java·设计模式·建造者模式
菜菜-plus14 小时前
java 设计模式 模板方法模式
java·设计模式·模板方法模式
萨达大14 小时前
23种设计模式-模板方法(Template Method)设计模式
java·c++·设计模式·软考·模板方法模式·软件设计师·行为型设计模式
机器视觉知识推荐、就业指导16 小时前
C++设计模式:原型模式(Prototype)
c++·设计模式·原型模式
阳光开朗_大男孩儿16 小时前
组合模式和适配器模式的区别
设计模式·组合模式·适配器模式