设计模式之责任链的通用实践思考

责任链模式通常一般用在方法的拦截、监控、统计方面,比较典型的就是Spring的AOP拦截。

但写一些小的基础能力框架的时候,用AOP比较中,所以一般都是自己针对特定的功能写一些定制的责任链工具类,不太喜欢总是做一些定制化的东西,想着能不能简单定义一套标准,基于标准能够快速实现责任链的能力?

1、定义简单的链路控制类

该类是一套标准的控制类,主要负责流转链路执行走向

其中Supplier中是目标的执行方法

T 代表接口的标记也就是第二点的实现

java 复制代码
public class SampleBaseFilterChain<T extends SimpleChainFilterService> {
    /**
     * 拦截器
     */
    private final List<T> functionFilters;
    /**
     * 具体的执行方法
     */
    private final Supplier<Object> supplier;

    private int index = 0;

    public SampleBaseFilterChain(List<T> functionFilters, Supplier<Object> supplier) {
        this.functionFilters = functionFilters;
        this.supplier = supplier;
    }

	// 该方法是为了方便在Spring的IOC容器中直接根据类对象,从容器中获取相应的集合.
    public SampleBaseFilterChain(Class<T> clazz, Supplier<Object> supplier) {
        this.functionFilters = SpringUtils.getBeansOfType(clazz).values().stream().toList();
        this.supplier = supplier;
    }


    public Object doFilter(Object... objects) {

        if (CollectionUtils.isEmpty(functionFilters) || functionFilters.size() == index) {
            return supplier.get();
        }

        return functionFilters.get(index++).doFilter(this, objects);
    }

}

2、定义接口标准

这部分接口太过于抽象,比如你不知道参数具体是啥,可能需要针对下层实现才知道。

java 复制代码
public interface SimpleChainFilterService {
    Object doFilter(SampleBaseFilterChain<? extends SimpleChainFilterService> chain, Object... obj);
}

基于以上两点基本上确定了控制器和顶层接口的定义,该怎么玩呢?

java 复制代码
@Test
    public void doFilter() {
        List<SimpleChainFilterService> chainList = new ArrayList<>();

        chainList.add((chain, obj) -> {
            System.out.println("A-start-" + obj[0]);
            return chain.doFilter(obj);
        });

        chainList.add((chain, obj) -> {
            final Object o = chain.doFilter(obj);
            System.out.println("B-end-" + obj[0]);
            return o;
        });

        chainList.add((chain, obj) -> {
            System.out.println("C-start-" + obj[1]);
            final Object o = chain.doFilter(obj);
            System.out.println("C-end-" + obj[1]);
            return o;
        });

        SampleBaseFilterChain<SimpleChainFilterService> sampleFilterChain = new SampleBaseFilterChain<>(chainList, () -> "ok");

        final Object o = sampleFilterChain.doFilter("哈哈", 1);
        System.out.println("得到结果:" + o);

    }

打印结果:

tex 复制代码
A-start-哈哈
C-start-1
C-end-1
B-end-哈哈
得到结果:ok

3、接口标准优化

对于第二点的接口,太过于抽象,无法知道接口的具体参数,这对后续使用者实现来说会很麻烦。

这个时候,你可以针对特定的业务标准在下沉一层。

比如需要针对登录进行拦截

java 复制代码
public interface  LoginChain extends SimpleChainFilterService {
   @Override
   default Object doFilter(SampleBaseFilterChain<? extends SimpleChainFilterService> chain, Object... obj) {
       return doFilter(chain, (String) obj[0], (int) obj[1]);
   }
   public String doFilter(SampleBaseFilterChain<? extends SimpleChainFilterService> chain, String username, int id);
}

使用方式:

java 复制代码
// 前置拦截
List<LoginChain1> chainList1 = new ArrayList<>();
chainList1.add((chain, username, id) -> {
    System.out.println("login-start-" + username + "\t" + id);
    return chain.doFilter(username, id).toString();
});

// 后置拦截
chainList1.add((chain, username, id) -> {
    final String result = chain.doFilter(username, id).toString();
    System.out.println("login-end-" + username + "\t" + id);
    return result;
});

SampleBaseFilterChain<LoginChain1> sampleFilterChain = new SampleBaseFilterChain<>(chainList1, () -> {
    System.out.println("ok");
    return "ok";
});

final Object o = sampleFilterChain.doFilter("哈哈", 1);
System.out.println("得到结果:" + o);
tex 复制代码
login-start-哈哈	1
ok
login-end-哈哈	1
得到结果:ok

基于以上的定义,我们只需要编写SimpleChainFilterService实现即可,通过使用SampleBaseFilterChain 来触发控制流程的流转,就行了,不用每套责任链都要重写接口和控制链。

以上为个人实践思考,如果你有更好的方式,欢迎交流学习~

相关推荐
鲨鱼辣椒不吃辣c10 分钟前
拦截器魔法:Spring MVC中的防重放守护者
java·spring·mvc
winks316 分钟前
Spring Task的使用
java·后端·spring
秋意钟27 分钟前
Spring新版本
java·后端·spring
椰椰椰耶29 分钟前
【文档搜索引擎】缓冲区优化和索引模块小结
java·spring·搜索引擎
重生之绝世牛码41 分钟前
Java设计模式 —— 【结构型模式】外观模式详解
java·大数据·开发语言·设计模式·设计原则·外观模式
小蜗牛慢慢爬行1 小时前
有关异步场景的 10 大 Spring Boot 面试问题
java·开发语言·网络·spring boot·后端·spring·面试
shinelord明1 小时前
【再谈设计模式】享元模式~对象共享的优化妙手
开发语言·数据结构·算法·设计模式·软件工程
钱多多_qdd1 小时前
spring cache源码解析(四)——从@EnableCaching开始来阅读源码
java·spring boot·spring
程序猿进阶3 小时前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot