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

责任链模式通常一般用在方法的拦截、监控、统计方面,比较典型的就是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 来触发控制流程的流转,就行了,不用每套责任链都要重写接口和控制链。

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

相关推荐
范纹杉想快点毕业2 小时前
实战级ZYNQ中断状态机FIFO设计
java·开发语言·驱动开发·设计模式·架构·mfc
茂桑6 小时前
DDD领域驱动设计-基础设施层
设计模式·架构
shuair6 小时前
redis缓存预热、缓存击穿、缓存穿透、缓存雪崩
redis·spring·缓存
计算机程序设计小李同学6 小时前
基于 Spring Boot + Vue 的龙虾专营店管理系统的设计与实现
java·spring boot·后端·spring·vue
qq_12498707538 小时前
基于Java Web的城市花园小区维修管理系统的设计与实现(源码+论文+部署+安装)
java·开发语言·前端·spring boot·spring·毕业设计·计算机毕业设计
Chasmれ9 小时前
Spring Boot 1.x(基于Spring 4)中使用Java 8实现Token
java·spring boot·spring
计算机学姐9 小时前
基于SpringBoot的校园社团管理系统
java·vue.js·spring boot·后端·spring·信息可视化·推荐算法
落霞的思绪9 小时前
Spring AI Alibaba 集成 Redis 向量数据库实现 RAG 与记忆功能
java·spring·rag·springai
小温冲冲10 小时前
通俗且全面精讲工厂设计模式
设计模式
进击的小头10 小时前
设计模式与C语言高级特性的结合
c语言·设计模式