设计模式基础概念(行为模式):责任链模式(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. 客户端可以自行组装链, 或者从其他对象处获得预先组装好的链。 在后一种情况下, 你必须实现工厂类以根据配置或环境设置来创建链。

    • 客户端可以触发链中的任意处理者, 而不仅仅是第一个。 请求将通过链进行传递, 直至某个处理者拒绝继续传递, 或者请求到达链尾。
    • 由于链的动态性, 客户端需要准备好处理以下情况:
      • 链中可能只有单个链接
      • 部分请求可能无法到达链尾
      • 其他请求可能直到链尾都未被处理
相关推荐
on the way 12312 小时前
结构性设计模式之Flyweight(享元)
java·设计模式·享元模式
暴躁哥16 小时前
深入理解设计模式之访问者模式
设计模式·访问者模式
佩奇的技术笔记16 小时前
从Java的JDK源码中学设计模式之装饰器模式
java·设计模式·装饰器模式
on the way 12316 小时前
结构型设计模式之Proxy(代理)
设计模式·代理模式
YGGP19 小时前
【结构型模式】装饰器模式
设计模式
将编程培养成爱好1 天前
《复制粘贴的奇迹:小明的原型工厂》
c++·设计模式·原型模式
liang_jy1 天前
设计模式中的几大原则
设计模式·面试
huangyujun99201231 天前
设计模式杂谈-模板设计模式
java·设计模式
magic 2451 天前
Java设计模式:责任链模式
java·设计模式·责任链模式
YGGP1 天前
【结构型模式】代理模式
设计模式