责任链模式

引言

在软件开发过程中,经常会遇到需要对请求进行一系列处理的情况。例如,在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。

相关推荐
程序猿阿伟3 分钟前
《C++中的魔法:实现类似 Python 的装饰器模式》
java·c++·装饰器模式
Mr. zhihao5 分钟前
装饰器模式详解:动态扩展对象功能的优雅解决方案
java·开发语言·装饰器模式
2401_8576009512 分钟前
商场应急管理:SpringBoot技术解决方案
java·spring boot·后端
想做白天梦24 分钟前
多级反馈队列
java·windows·算法
潇雷26 分钟前
算法Day12|226-翻转二叉树;101-对称二叉树;104-二叉树最大深度;111-二叉树最小深度
java·算法·leetcode
一颗甜苞谷33 分钟前
开源一套基于若依的wms仓库管理系统,支持lodop和网页打印入库单、出库单的源码
java·开源
半夏之沫35 分钟前
✨最新金九银十✨大厂后端面经✨
java·后端·面试
计算机学姐1 小时前
基于uniapp微信小程序的餐厅预约点餐系统
java·spring boot·微信小程序·小程序·java-ee·uni-app·tomcat
小宇1 小时前
The valid characters are defined in RFC 7230 and RFC 3986
java·开发语言·后端·tomcat