责任链模式(ChainOfResponsibility)

275

责任链模式(ChainOfResponsibility)

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

/**
 * 责任链模式
 *
 * @author CAI
 * @time 2020/10/31
 */
public class ChainOfResponsibilityPattern {

    private static Server server;

    private static void init() {
        server = new Server();
        server.register("admin", "admin");
        server.register("root", "admin");
        server.register("jack", "heel");

        Middleware middleware = new ThrottlingMiddleware(2);
        middleware.linkWith(new UserExistsMiddleware(server)).linkWith(new RoleCheckMiddleware());

        server.setMiddleware(middleware);
    }

    public static void main(String[] args) {
        init();

        boolean success;
        Scanner in = new Scanner(System.in);
        do {
            System.out.print("Enter user :");
            String user = in.nextLine();
            System.out.print("Input password : ");
            String password = in.nextLine();

            success = server.login(user, password);

        } while (!success);
    }
}

/**
 * 中间类
 */
abstract class Middleware {

    /**
     * 继任者
     */
    private Middleware next;

    public Middleware linkWith(Middleware next) {
        this.next = next;

        return next;
    }

    /**
     * 用户认证
     *
     * @param name 用户
     * @param password 密码
     * @return 认证结果
     */
    public abstract Boolean check(String name, String password);

    /**
     * 将认证传递给继任者
     *
     * @param name 用户名
     * @param password 密码
     * @return 继任者的认证结果
     */
    protected Boolean checkNext(String name, String password) {
        if (name == null) {
            return true;
        }

        return next.check(name, password);
    }
}

/**
 * 限制流量
 */
class ThrottlingMiddleware extends Middleware {

    /**
     * 请求间隔
     */
    private final Integer requestPerMinute;

    /**
     * 请求次数
     */
    private Integer request;

    /**
     * 当前时间
     */
    private Long currentTime;

    public ThrottlingMiddleware(int requestPerMinute) {
        this.requestPerMinute = requestPerMinute;
        this.currentTime = System.currentTimeMillis();
        this.request = 0;
    }

    @Override
    public Boolean check(String name, String password) {
        if (System.currentTimeMillis() > currentTime + 60_000) {
            request = 0;
            currentTime = System.currentTimeMillis();
        }

        request++;

        if (request > requestPerMinute) {
            System.out.println("请求次数超过限制.");
            Thread.currentThread().stop();
        }

        return checkNext(name, password);
    }
}

/**
 * 检查用户信息
 */
class UserExistsMiddleware extends Middleware {

    private final Server server;

    public UserExistsMiddleware(Server server) {
        this.server = server;
    }

    @Override
    public Boolean check(String user, String password) {
        if (!server.hasUser(user)) {
            System.out.println("该用户未注册!");

            return false;
        }

        if (!server.isValidPassword(user, password)) {
            System.out.println("密码错误!");

            return false;
        }

        return checkNext(user, password);
    }
}

class RoleCheckMiddleware extends Middleware {

    @Override
    public Boolean check(String user, String password) {
        if ("root".equals(user) || "admin".equals(user)) {
            System.out.println("Hello admin!");

            return true;
        }

        System.out.println("Hello user!");
        return checkNext(user, password);
    }
}

class Server {

    /**
     * 用户
     */
    private Map<String, String> users = new HashMap<>();

    /**
     * 中间件
     */
    private Middleware middleware;

    public void setMiddleware(Middleware middleware) {
        this.middleware = middleware;
    }

    /**
     * 登录
     *
     * @param user 用户
     * @param password 密码
     * @return 登录结果
     */
    public Boolean login(String user, String password) {
        if (middleware.check(user, password)) {
            System.out.println("认证通过,用户登录成功!");

            return true;
        }

        return false;
    }

    /**
     * 注册
     *
     * @param user 用户
     * @param password 密码
     */
    public void register(String user, String password) {
        users.put(user, password);
    }

    /**
     * 判断用户是否存在
     *
     * @param user 用户
     * @return true:存在
     */
    public Boolean hasUser(String user) {

        return users.containsKey(user);
    }

    /**
     * 判断密码是否合法
     *
     * @param user 密码
     * @return 密码合法性
     */
    public Boolean isValidPassword(String user, String password) {

        return users.get(user).equals(password);
    }
}
  1. 处理者(Handler):声明所有具体处理者的通用接口。该接口通常包含单个方法用于处理请求,但有时还会包含一个设置链上下一个处理者的方法。
  2. 基础处理者(中间类):是一个可选的类,通常定义一个保存对于下一个处理者引用的成员变量。客户端通常可以使用该类定义的方法创建责任链,类中可以定义默认的处理行为如:确定存在下一个处理者在进行传递。
  3. 具体处理者(ThrottlingMiddleware等):实现请求的具体处理。每个处理者收到请求后必须决定处理请求或传递该请求;处理者通常是独立且不可变的,需要通过构造函数一次性获取所有必要的数据。
  4. 客户端:根据业务逻辑,动态或一次性生成责任链。请求可以发给链上的任意一个处理者,而非第一个处理者。

应用场景

  1. 当程序需要使用不同方式处理不同种类请求,且请求类型和顺序预先并不知道即:不知道具体的处理者,可以使用责任链模式。
    • 该模式能将多个处理者连接形成一条处理链,接收到请求后,会询问每个处理者能否处理该请求;这样所有的处理者都有机会处理该请求。发送者不必显示地指定具体的接收者,也使得两者间不存在耦合。
  2. 当必须按顺序执行多个处理者时,可以使用该模式。
    • 无论以何种顺序将处理者连接成一条链,所有请求都会严格按照顺序通过链上的处理者。
  3. 如果所需的处理者及其顺序必须在运行时改变,可以使用责任链模式。
    • 如果在处理者类中有对引用成员变量的设定方法,就能动态地插入或移除处理者,或改变其顺序。

优缺点

  • 优点:
    • 能控制请求处理的顺序。
    • 可以请求的发起者和执行者进行解耦,满足单一职责原则。
    • 再不更改现有代码的情况下可以新增处理者,满足了开闭原则。
  • 缺点:若责任链配置不当,一个请求可能到了链的末端都未被处理。

在 JAVA 中的应用

java核心库为例:

  1. javax.servlet.Filter doFilter()
  2. java.util.logging.Logger log()