责任链模式极简教程

简介: 责任链模式( Chain of Responsibility Pattern)属于行为型设计模式。顾名思义就是生成一个“链”,然后让请求沿着链传递,传递的过程其实就是挨个进入和离开并列的节点中,这些节点被称之为“责任”,每一个节点有权力自己判断是否进行处理。请求者无需关心,也无法知道到底有多少个处理节点。

简介

责任链模式( Chain of Responsibility Pattern)属于行为型设计模式。顾名思义就是生成一个“链”,然后让请求沿着链传递,传递的过程其实就是挨个进入和离开并列的节点中,这些节点被称之为“责任”,每一个节点有权力自己判断是否进行处理。请求者无需关心,也无法知道到底有多少个处理节点。

优点:

  • 只需要将请求发送到链上即可,⽆须关⼼请求的处理细节,降低了耦合度
  • 链中节点可以设置顺序,增加了灵活度
  • 链中的节点可以增减,增加了可扩展性
  • 简化了对象之前的连接,可避免出现众多的if或者 if-else 情况
  • 一个节点处理某一个细粒度任务,符合单一职责原则

缺点:

  • 责任作为处理单元,会分散到各个节点中,每一个节点功能单一,多个节点共同完成了一个处理逻辑,节点越多越膨胀
  • 可能会出现请求跑完整个链路都得不到处理的情况
  • 增加了请求者复杂度,由原来的请求资源改为了请求一个链路

类图

责任链模式类图

应用场景

  • SpringBoot 框架中的各种拦截器、各种过滤器,如 ApplicationFilterChain
  • 日志处理

  • 参数校验

举例

以SpringBoot项目举例如何在代码中编写责任链模式

业务描述

一个消息推送的业务场景,当订单创建后需要向多个端推送消息,如站内消息、微信模板消息等。

  • 请求者:(客户端)就是订单创建者
  • 责任:推送站内消息、推送微信模板消息。做具体业务实现的对象称之为责任
  • 链:维护各个“责任”,让他们协同工作,哪些责任需要被创建、如何排序、链路如何传递等

代码实现

本例中用到了filter作为链节点的修饰词,这里是参考了SprinBoot 框架 ApplicationFilterChain 的命名,其实更加合适的名词是 handler

定义消息通知接口


public interface NoticeFilter {
    Integer getShort();
    void pushMsg(AbstractNoticeDto model, NoticePushChain chain , Integer index);
}
  • 此接口为各个责任类的共同父接口,用来定义消息通知的规范
  • getShort 方法获取本责任的排序,需要实现类自行实现
  • 定义了一个pushMsg 的方法,用来实际干活,将消息推送到特定的平台。此方法入参中有一个 chain ,用来在运行时获取处理链路

创建站内消息通知实现


@Slf4j
@AllArgsConstructor
@Service
public class MsgNoticeFilter implements NoticeFilter {

    @Override
    public Integer getShort() {
        return 1;
    }

    @Override
    public void pushMsg(AbstractNoticeDto model, NoticePushChain chain, Integer index) {
        log.debug("执行 msg 消息推送");
        //msgNoticeService.createMessage(model);
        chain.doFilter(model, chain, index);
    }
}
  • MsgNoticeFilter 类为站内消息推送实现类
  • 重写 getShort 方法,设置自己的顺序
  • 重写 pushMsg 方法,编写具体的消息推送逻辑
  • 消息推送完毕之后,调用 chain.doFilter 方法,将请求沿着链路传递

创建微信消息通知实现


@Slf4j
@AllArgsConstructor
@Service
public class WechatNoticeFilter implements NoticeFilter {
    @Override
    public Integer getShort() {
        return 2;
    }
    @Override
    public void pushMsg(AbstractNoticeDto model, NoticePushChain chain, Integer index) {
        log.debug("执行 wechat 消息通知");
        //wechatNoticeService.pushNotice(model);
        chain.doFilter(model, chain, index);
    }
}
  • 思路和 MsgNoticeFilter 一样

创建责任链实现类


@Service
public class NoticePushChain implements ApplicationContextAware {

    private List<NoticeFilter> filters;

    /**
     * 当前过滤器 index
     */
    private int currentIndex = 0;

    /**
     * 下一个过滤器 index
     */
    private int nextIndex = 0;

    /**
     * 总过滤器数量
     */
    private int total = 0;

    public void doFilter(AbstractNoticeDto model, NoticePushChain chain, Integer index) {
        if (index == null || index < 0) {
            index = 0;
        }
        if (index < filters.size()) {
            nextIndex = index + 1;
            currentIndex = index;
            index++;
            filters.get(index - 1).pushMsg(model, chain, index);
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, NoticeFilter> serviceMap = applicationContext.getBeansOfType(NoticeFilter.class);
        filters = new ArrayList<>(serviceMap.values());
        filters = filters.stream().sorted(Comparator.comparing(NoticeFilter::getShort)).collect(Collectors.toList());
        total = filters.size();
    }
}
  • 创建NoticePushChain类用来维护各个责任,此类需要注入到容器中,供请求者调用。有了链路之后,请求者由原来的调用 service ,改为调用链路,某种层面来说,链路也是提供服务 ,有点像 DDD 中的 application层的概念
  • 定义变量filters,存放所有可用的责任实现类,为一个list
  • 定义 currentIndex 用来在运行时记录当前处理节点的索引
  • 定义nextIndex 用来在运行时记录下一个处理节点的索引
  • 定义total 用来在运行时记录一共有多少个处理节点
  • 此类需要实现 ApplicationContextAware 接口,用于在程序启动完毕后收集所有的责任实现类,这里就可以做业务逻辑处理扩展,比如哪些责任实现类需要存放到 filters 中可以自定义

  • 重写 setApplicationContext 方法,并通过 getBeansOfType 方法获取责任实现类

  • 通过对 filters 遍历来实现为链路上所有节点排序

  • 定义 doFilter 方法,此方法和节点能够沿着链路传递的核心,参数中的 chain 会在各个处理节点中挨个向下传递,每处理完一个节点就回调 doFilter 方法,再由控制 index实现链路向下传递。此方法需要暴露出去,供请求者调用

  • 本文中说到的 节点和责任是一个概念,都是指实际处理业务逻辑的类

模拟调用


@Autowired
NoticePushChain noticePushChain;



@GetMapping("/createOrder")
public String createOrder() {
    AbstractNoticeDto model = new AbstractNoticeDto();
    noticePushChain.doFilter(model, noticePushChain, null);
    return IdUtil.fastSimpleUUID();
}
  • 注入NoticePushChain 并模拟调用
  • 请求先到 chain ,而后将根据顺序进入第一个节点,第一个节点处理完毕,回到chain ,而后进入第二个节点,依此类推。

代码

https://gitee.com/naylor_personal/ramble-spring-boot/tree/master/chain-pattern

目录
相关文章
|
7月前
|
设计模式 Java
【设计模式系列笔记】责任链模式
责任链模式是一种行为设计模式,它允许你将请求沿着处理者链进行传递,直到有一个处理者能够处理它。每个处理者都有一个对下一个处理者的引用。责任链模式常用于处理请求的场景,例如在一个请求需要经过多个步骤或者多个对象来处理的情况下。
83 0
|
7月前
|
设计模式 Java
深入浅出职责链模式
深入浅出职责链模式
57 0
|
1月前
|
设计模式 数据安全/隐私保护
责任链模式实战:在项目中的应用与技巧
在软件工程中,责任链模式(Chain of Responsibility)是一种对象行为型设计模式,它允许多个对象有机会处理请求,从而避免请求发送者与接收者之间的耦合。这种模式在处理复杂的业务逻辑和系统解耦方面非常有用。本文将探讨责任链模式的基本概念、应用场景以及在实际项目中的应用技巧。
40 4
|
1月前
|
设计模式 数据安全/隐私保护
探索责任链模式:在项目中的应用与实践
在软件设计模式中,责任链模式(Chain of Responsibility)是一种对象行为型模式,它允许一个请求沿着链式结构的多个对象传递,直到有一个对象处理它为止。这种模式在实际项目中有着广泛的应用,尤其是在处理复杂的业务逻辑和解耦系统中。本文将分享责任链模式的基本概念、应用场景以及在项目中的实践案例。
55 5
|
6月前
|
设计模式 Java 中间件
深入探索Java设计模式:责任链模式解析与实践
深入探索Java设计模式:责任链模式解析与实践
57 0
|
7月前
|
设计模式 Java 测试技术
浅谈设计模式 - 责任链模式(十四)
浅谈设计模式 - 责任链模式(十四)
72 0
|
7月前
|
设计模式 Java
Java设计模式【十四】:责任链模式
Java设计模式【十四】:责任链模式
54 0
|
设计模式
设计模式系列教程(14) - 观察者模式
设计模式系列教程(14) - 观察者模式
35 0
|
设计模式 安全 Java
深入浅出设计模式 - 责任链模式
深入浅出设计模式 - 责任链模式
9406 1
深入浅出设计模式 - 责任链模式
|
设计模式 前端开发 JavaScript
前端实现设计模式之责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许将请求沿着处理链传递,直到有一个处理者能够处理该请求为止。责任链模式将请求的发送者和接收者解耦,使得多个对象都有机会处理请求。在前端开发中,责任链模式常用于处理事件、请求拦截和错误处理等场景。本文将介绍如何在前端中实现责任链模式,并提供具体的代码示例和解读。
218 0