Java设计模式【责任链模式】

一、前言

1.1 背景

  • 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定
  • 不明确指定接收者的情况下,向多个对象中的一个提交一个请求
  • 可动态指定一组对象处理请求

1.2 简介

职责链模式是一种行为型设计模式,它通过将请求的发送者和接收者解耦来实现请求的处理。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

优点

  • 降低系统的耦合度
  • 提高代码的可扩展性和可维护性
  • 具备链式传递处理请求功能,请求发送者无需知晓链路结构,只需等待请求处理结果
  • 链路结构灵活,可以通过改变链路结构动态地新增或删减责任
  • 易于扩展新的请求处理类(节点),符合开闭原则

缺点

  • 责任链太长或者处理时间过长,会影响整体性能
  • 如果节点对象存在循环引用时,会造成死循环,导致系统崩溃

组成部分

  • 抽象处理者(Handler):定义一个处理请求的接口,包含抽象处理方法和一个后继连接
  • 具体处理者(Concrete Handler):实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者
  • 客户类(Client):创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程

二、案例代码

java 复制代码
package com.qiangesoft.design.behavioral.responsibilitychain;

import java.util.HashMap;
import java.util.Map;

/**
 * 客户类
 * 
 * ps:责任链模式
 */
public class Chain {

    public static void main(String[] args) {
        // 模拟请求
        Request request = new Request();
//        request.setPath("/api/news");
        request.setPath("/user/1");
        Map<String, String> header = new HashMap<>();
        header.put("token", "111111");
        request.setHeader(header);

        // 组装责任链
        Handler handler = getHandlerChain();

        // 提交请求
        handler.doHandler(request);

        System.out.println("***执行了接口方法***");
    }

    /**
     * 组装责任链
     *
     * @return
     */
    private static Handler getHandlerChain() {
        Handler tokenHandler = new TokenHandler();
        Handler authHandler = new AuthHandler();
        Handler logHandler = new LogHandler();
        tokenHandler.setNext(authHandler)
                .setNext(logHandler);
        return tokenHandler;
    }
}

/**
 * 抽象处理者
 */
abstract class Handler {

    protected Handler next;

    public Handler setNext(Handler next) {
        this.next = next;
        return next;
    }

    protected abstract void doHandler(Request request);
}

/**
 * 具体处理者:token校验
 */
class TokenHandler extends Handler {
    @Override
    public void doHandler(Request request) {
        // 有些接口无需登录
        String path = request.getPath();
        if (path.startsWith("/api")) {
            return;
        }

        try {
            // token校验(模拟)
            String token = request.getHeader().get("token");
            if (token == null || "".equals(token)) {
                System.out.println("用户未登录!");
                return;
            }
            if (!"111111".equals(token)) {
                System.out.println("登录已失效!");
                return;
            }
            String username = "admin";
            AuthenticationContextHolder.set(username);
            System.out.println("token校验成功!");

            if (next != null) {
                next.doHandler(request);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            AuthenticationContextHolder.remove();
        }
    }
}

/**
 * 具体处理者:权限校验
 */
class AuthHandler extends Handler {
    @Override
    public void doHandler(Request request) {
        String username = AuthenticationContextHolder.get();
        if (!"admin".equals(username)) {
            System.out.println("当前用户无权限!");
            return;
        }

        System.out.println("权限校验成功!");

        if (next != null) {
            next.doHandler(request);
        }
    }
}

/**
 * 具体处理者:日志记录
 */
class LogHandler extends Handler {
    @Override
    public void doHandler(Request request) {
        String username = AuthenticationContextHolder.get();
        System.out.println("记录日志:请求【xxx接口】 操作人【" + username + "】!");

        if (next != null) {
            next.doHandler(request);
        }
    }
}

/**
 * 模拟request对象
 */
class Request {

    private String path;

    private Map<String, String> header;

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public Map<String, String> getHeader() {
        return header;
    }

    public void setHeader(Map<String, String> header) {
        this.header = header;
    }
}

/**
 * 线程本地变量:用户信息
 */
class AuthenticationContextHolder {
    private static final ThreadLocal<String> CURRENT_USER = new ThreadLocal<>();

    public static String get() {
        return CURRENT_USER.get();
    }

    public static void set(String user) {
        CURRENT_USER.set(user);
    }

    public static void remove() {
        CURRENT_USER.remove();
    }
}

三、总结

应用场景

  • 过滤器(Filter):在Servlet中,过滤器就是使用责任链模式实现的。每个过滤器都可以决定是否处理请求,或者将其转发给下一个过滤器进行处理。
  • 拦截器(Interceptor):在Spring框架中,拦截器就是使用责任链模式实现的。拦截器可以对请求进行预处理或后处理,也可以将请求转发给下一个拦截器进行处理。
  • 异常处理(Exception Handling):在Java中,可以使用责任链模式来处理异常。首先,程序先尝试使用自定义的异常处理器来处理异常,如果该处理器无法处理异常,则将其转发给下一个处理器进行处理。
相关推荐
憨子周35 分钟前
2M的带宽怎么怎么设置tcp滑动窗口以及连接池
java·网络·网络协议·tcp/ip
霖雨2 小时前
使用Visual Studio Code 快速新建Net项目
java·ide·windows·vscode·编辑器
SRY122404192 小时前
javaSE面试题
java·开发语言·面试
Fiercezm3 小时前
JUC学习
java
无尽的大道3 小时前
Java 泛型详解:参数化类型的强大之处
java·开发语言
ZIM学编程3 小时前
Java基础Day-Sixteen
java·开发语言·windows
我不是星海3 小时前
1.集合体系补充(1)
java·数据结构
P.H. Infinity3 小时前
【RabbitMQ】07-业务幂等处理
java·rabbitmq·java-rabbitmq
爱吃土豆的程序员3 小时前
java XMLStreamConstants.CDATA 无法识别 <![CDATA[]]>
xml·java·cdata
2401_857610034 小时前
多维视角下的知识管理:Spring Boot应用
java·spring boot·后端