设计模式:诠释抽象责任链模式的实际应用场景

一、什么是责任链模式?

责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许多个对象按照顺序处理请求,并且每个对象可以选择自己是否处理该请求或将其传递给下一个对象。这种模式将请求的发送者和接收者解耦,同时提供了更大的灵活性和可扩展性。

责任链模式通过将多个处理请求的对象组成一条链,使请求在链上传递,直到有一个对象处理它为止。每个处理对象都负责判断自己能否处理该请求,如果可以则进行处理,否则将请求传递给下一个处理对象。这样,请求发送者无需知道具体的处理对象,只需将请求发送到责任链上即可。

责任链模式包含以下角色:

  • 抽象处理者(Handler) :定义一个处理请求的接口,并持有下一个处理者的引用。
  • 具体处理者(Concrete Handler) :实现抽象处理者的接口,在处理请求前判断自己是否能够处理该请求,如果可以则进行处理,否则将请求传递给下一个处理者。

通过责任链模式,我们可以动态地组合处理对象,灵活地配置处理流程,这种解耦使得系统更加灵活和可扩展,一起看下责任链模式的执行流程。

设计模式只是帮助减少代码的复杂性,让其满足开闭原则,提高代码的扩展性。如果不使用同样可以完成需求。

责任链模式的应用场景

  1. 多个对象可以处理一个请求,但具体由哪个对象处理该请求在运行时自动确定。
  2. 可动态指定一组对象处理请求,或添加新的处理者。
  3. 需要在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。

假设业务场景是这样的,我们C端用户扫码进来选择套餐启动设备,系统会处于一个上游检测校验服务,判断是否满足相关复杂的套餐计算后才决定是否向用户推荐VIP活动套餐,因此会根据入参做一系列的check校验逻辑,从系统业务交谈规则上看,我简化了主要需要支持一下几种condition校验规则:

  1. 请求参数必填校验,如果数据无法满足业务所必须字段要求,数据一旦落入库中就会产生一系列问题。
  2. 当前活动信息校验,比如商家是否参与活动、活动配置信息是否正常、活动是否处于上架状态等。
  3. 时间校验,比如当前时间是否处于活动的开放时间范围内。
  4. 设备是否正常存在。
  5. 活动配置设备类型、场地类型限制校验。
  6. 次数校验,用户参与活动次数是否已经达到上限。

如果不使用责任链模式,上面说的真实同步场景面临两个问题:

  1. 如果把上述说的代码逻辑校验规则写到一起,毫无疑问这个类或者说这个方法函数奇大无比 。减少代码复杂性一贯方法是:将大块代码逻辑拆分成函数,将大类拆分成小类,是应对代码复杂性的常用方法。如果此时说:可以把不同的校验规则拆分成不同的函数,不同的类,这样不也可以满足减少代码复杂性的要求么。这样拆分是能解决代码复杂性,但是这样就会面临第二个问题
  2. 开闭原则:添加一个新的功能应该是,在已有代码基础上扩展代码,而非修改已有代码。大家设想一下,假设你写了三套校验规则,运行过一段时间,这时候领导让加第四套,是不是要在原有代码上改动。

综上所述,在合适的场景运用适合的设计模式,能够让代码设计复杂性降低,变得更为健壮。朝更远的说也能让自己的编码设计能力有所提高。

使用责任链模式改造优点

  1. 将请求与处理解耦。
  2. 请求处理者(节点对象)只需要关注自己感兴趣的请求进行处理即可,对于不感兴趣的请求,转发给下一个节点。
  3. 具备链式传递处理请求功能,请求发送者无需知晓链路结构,只需等待请求处理结果。
  4. 链路结构灵活,可以通过改变链路的结构动态的新增或删减责任。
  5. 易于扩展新的请求处理类(节点),符合开闭原则

二、责任链模式模版

对于不同业务场景的责任链模式,我自定义了一套模版,适用于不同场景直接可以套用即可。

第一步:定义@Duty注解

一切从注解开始,需要自定义一个注解@Duty,这个注解由Spring@Component注解修饰,也就是标记了这个自定义注解的类,都是交给Springbean容器去管理 。

注解中,有两个属性:

  • mark :定义相同的mark标记类型的bean,会被放到一个责任链集合中。
  • order :同一个责任链集合中,bean的排序,数值越小,会放到链路最先的位置,优先处理。

第二步:定义一个顶层的抽象接口,入参为两个泛型参数,方便后续自定义扩展使用。

第三步:定义一个责任链处理器Bean的管理上下文AbstractChainContext,用来存放不同业务下的责任链路集合。在该类中,有一个Map和两个方法。

  • chainHandlerContainer :这个map会存放责任链路中,具体的执行类,key是注解@Duty中定义的mark值,value是标记了@Duty注解的bean集合,也就是具体的执行类集合。
  • applyHandleMap :传入具体执行bean的集合,存放在map中。
  • executeHandle :从chainHandlerContainer这个map中找到具体的执行bean集合,并依次执行。

第四步:定义一个配置类DutyDesignPatternConfiguration,用于装配上面的责任链管理器上下文AbstractChainContext

第五步:自定义不同责任链处理类

具体的处理类有:ActivityViewCheckParamAvailableChainHandlerActivityViewCheckActivityMerchantChainHandlerActivityViewCheckActivityGroupTypeChainHandlerActivityViewCheckActivityUpperLimitChainHandler,我这里以其中一个责任链的处理类为例,在具体处理类上标记自定义注解@Duty,该类会被注入到bean容器中,实现AbstractChainHandler接口,只需关心自己的handle方法,处理具体的业务逻辑。

第六步:具体调用

三、业务场景代码示例 - C端符合条件活动展示校验过滤器

ActivityViewCheckParamAvailableChainHandler参数校验处理类

ActivityViewCheckActivityMerchantChainHandler活动商家信息校验处理类

ActivityViewCheckActivityGroupTypeChainHandler场地和设备类型校验处理类

ActivityViewCheckActivityUpperLimitChainHandler商家参与活动次数校验处理类

实际调用

四、总结

责任链模式是一种强大而灵活的设计模式,它可以帮助我们构建具有可扩展性和低耦合度的处理流程。通过将请求发送方和接收方解耦,责任链模式允许我们动态地改变或扩展请求的处理顺序,从而实现更高度的灵活性和可维护性。

责任链模式的优点在于其低耦合性、灵活性和可扩展性,使得我们能够更加轻松地管理和组织复杂的处理流程。然而,也要注意其缺点,即请求未必被处理和对处理顺序敏感的特点。

最重要的是,在实际应用中根据具体需求合理运用责任链模式,结合其他设计模式,以便在代码结构和可维护性上取得更好的效果。本文主要是通过一个责任链模式模板和具体实战代码来诠释什么是《责任链模式》,好了,今天的分享就到此结束了,如果文章对你有所帮助,欢迎:点赞👍+评论💬+收藏❤ ,我是:IT_sunshine,我们下期见!

相关推荐
字节全栈_mMD12 分钟前
Flink Connector 写入 Iceberg 流程源码解析_confluent icebergsinkconnector
java·大数据·flink
轩情吖13 分钟前
二叉树-堆(补充)
c语言·数据结构·c++·后端·二叉树··排序
SomeB1oody24 分钟前
【Rust自学】19.2. 高级trait:关联类型、默认泛型参数和运算符重载、完全限定语法、supertrait和newtype
开发语言·后端·rust
小园子的小菜25 分钟前
RocketMQ中的NameServer主要数据结构
java·中间件·rocketmq·java-rocketmq
平凡君39 分钟前
缓存的今生今世
java·spring·缓存
纠结哥_Shrek1 小时前
Java 有很多常用的库
java·开发语言
爱是小小的癌2 小时前
Java-数据结构-优先级队列(堆)
java·前端·数据结构
天乐敲代码2 小时前
JAVASE入门十五脚-网络TCP,UDP,,Lambda
java
加油,旭杏2 小时前
【go语言】函数
开发语言·后端·golang
2501_903238653 小时前
自定义登录页面的Spring Security实践
java·后端·spring·个人开发