责任链模式

引言

在软件开发过程中,经常会遇到需要对请求进行一系列处理的情况。例如,在Web应用中,用户的请求可能需要经过身份验证、权限检查、数据校验等步骤。为了使代码结构清晰、降低耦合度、提高可扩展性,可以使用责任链模式来解决此类问题。

责任链模式定义

责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它通过将多个处理者(Handler)按照顺序组成一条链,当有请求发生时,沿着这条链依次传递,直到有处理者处理它或处理链结束。该模式使请求的发送者和接收者解耦,客户端无需知道是哪一个处理者最终处理了请求,增强了系统的灵活性。

比如在一个采购系统中,用户需要进行采购下单,对采购的商品会进行很多校验,比如用户是否符合采购用户标准,用户采购的订单库存是否充足,用户需要送达的地址是否可以送到等等一系列校验。按照需求快速开发我们就会在一个校验的方法里面,判断上述一系列条件是否满足,满足才可以生成订单。后面系统进行二次迭代,vip 用户不需要下单,也不需要进行地址校验,这时候可能会加入一个if vip user 的判断 然后再决定是否执行校验,这样简单一次代码结果还好,但是随着系统的不断迭代,特定场景的订单越来越多,判断条件也越加越多,于是乎代码结果就变得难以阅读和维护。

参考Servlet 的Filter + FilterChain, 可以构建一个订单创建的职责链路,根据业务类型来指定对应的职责链路。

Servlet 里面的Filter 和FilterChain 使用的就是责任链模式。每一个职责可以组装,比如filterchain 也有不同的实现

  • Filter 接口 -> 实现处理过程
  • FilterChain 接口 -> 定义调用链路 责任链模式建议你将这些处理者连成一条链。 链上的每个处理者都有一个成员变量来保存对于下一处理者的引用。 除了处理请求外, 处理者还负责沿着链传递请求。 请求会在链上移动, 直至所有处理者都有机会对其进行处理。

写点代码

以订单创建为例子,会对订单的信息校验,然后再进行创建,如果不满足条件则退出,每种特定的行为的处理都会影响订单创建的结果。

快速开发if-else 一把锁

java 复制代码
public class OrderService {  
    void  creteOrder() {  
        OrderBO orderBO = new OrderBO();  
        if (checkState(orderBO)) {  
            //do something  
        }  
          
        if(checkAddress(orderBO)) {  
            //do something  
        }  
          
        if (checkXXX(orderBO)) {  
              
        }  
          
        //create order         
    }  
  
    private boolean checkXXX(OrderBO orderBO) {  
        return false;  
    }  
  
    private boolean checkAddress(OrderBO orderBO) {  
        return false;  
    }  
  
    private boolean checkState(OrderBO orderBO) {  
        return false;  
    }  
}

使用责任链模式拆分业务逻辑

  • OrderBO ,订单业务对象

  • OrderFilter ,订单处理过滤器接口

  • OrderAddressFilter 实现 OrderFilter

  • OrderStateFilter 实现OrderFilter

  • OrderFilterChain构建订单过滤链路,

    • 包含doFilter 和addFilter 方法,维护一个过滤器链表
  • OrderFilterTest指定需要的链路,然后执行过滤。具体代码如下所示

java 复制代码
//订单创建过滤器
public interface OrderFilter {  
  
    void doFilter(OrderBO order, OrderFilterChain chain);  
}
java 复制代码
​
//地址校验过滤器
@Slf4j  
@Component(OrderFilterConstant.ADDRESS)  
public class OrderAddressFilter implements OrderFilter {  
  
    @Override  
    public void doFilter(OrderBO order, OrderFilterChain orderFilterChain) {  
        log.info("执行地址过滤");  
        orderFilterChain.doFilter(order);  
    }  
}
less 复制代码
//订单状态校验过滤器
@Component(OrderFilterConstant.State)  
@Slf4j  
public class OrderStateFilter implements OrderFilter {  
    @Override  
    public void doFilter(OrderBO order, OrderFilterChain orderFilterChain) {  
        log.info("执行订单状态过滤");  
        orderFilterChain.doFilter(order);  
    }  
}

订单创建责任链

java 复制代码
@Slf4j  
@Component  
public class OrderFilterChain {  
  
    private int size;  
  
    private int position = 0;  
  
    private OrderFilter[] orderFilters = new OrderFilter[10];  
  
  
    public void doFilter(final OrderBO order) {  
        //必须加判断,否则链式调用会死循环,直到StackOverflow  
        if (this.position < this.size) {  
            OrderFilter orderFilter = orderFilters[position++];  
            orderFilter.doFilter(order, this);  
        }  
  
    }  
  
    public void addFilter(OrderFilter orderFilter) {  
        if (orderFilters.length == size) {  
            OrderFilter[] newOrderFilters = new OrderFilter[size + 10];  
            System.arraycopy(orderFilters, 0, newOrderFilters, 0, size);  
            orderFilters = newOrderFilters;  
        }  
        orderFilters[size++] = orderFilter;  
    }  
}

客户端测试代码

java 复制代码
​
@SpringBootTest  
public class OrderFilterTest {  
    @Autowired  
    private OrderFilterChain orderFilterChain;  
    @Autowired  
    private Map<String, OrderFilter> orderFilterMap;  
    @Autowired  
    private List<OrderFilter> orderFilters;  
    @Test  
    public void test() {  
        for (OrderFilter orderFilter : orderFilters) {  
            orderFilterChain.addFilter(orderFilter);  
        }  
//        orderFilterChain.addFilter(orderFilterMap.get(OrderFilterConstant.ADDRESS));  
//        orderFilterChain.addFilter(orderFilterMap.get(OrderFilterConstant.State));  
        orderFilterChain.doFilter(null);  
    }  
}

如果想要指定新的责任链,比如A业务不需要进行某个校验,那么在client 调用的时候,就不要添加到filterChain 即可

总结

在上面的案例中,我们把订单创建的每一个职责抽取成了单独的Filter ,每一个filter 可以通过FilterChain 进行链式调用。如果后续有新的责任链路的时候,可以在调用方指定校验链路的顺序和类型,实现对应的业务逻辑处理。

在使用责任链模式之后,后续迭代时既不需要修改原有的代码,也可以重新编排新的FilterChain。

相关推荐
P7进阶路1 小时前
Tomcat异常日志中文乱码怎么解决
java·tomcat·firefox
小丁爱养花1 小时前
Spring MVC:HTTP 请求的参数传递2.0
java·后端·spring
CodeClimb1 小时前
【华为OD-E卷 - 第k个排列 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
等一场春雨1 小时前
Java设计模式 九 桥接模式 (Bridge Pattern)
java·设计模式·桥接模式
带刺的坐椅2 小时前
[Java] Solon 框架的三大核心组件之一插件扩展体系
java·ioc·solon·plugin·aop·handler
不惑_2 小时前
深度学习 · 手撕 DeepLearning4J ,用Java实现手写数字识别 (附UI效果展示)
java·深度学习·ui
费曼乐园3 小时前
Kafka中bin目录下面kafka-run-class.sh脚本中的JAVA_HOME
java·kafka
feilieren3 小时前
SpringBoot 搭建 SSE
java·spring boot·spring
阿岳3163 小时前
Java导出通过Word模板导出docx文件并通过QQ邮箱发送
java·开发语言
Amor风信子4 小时前
华为OD机试真题---战场索敌
java·开发语言·算法·华为od·华为