【设计模式】责任链模式
简介
责任链模式是行为型设计模式(关注对象之间的通信)中的一种
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
设计模式参考:https://www.runoob.com/design-pattern/design-pattern-intro.html
应用场景
Java Web中的Servlet Filter
Spring Security中的 Filter Chain
案例Demo
下单支付场景中,往往要经历以下几个步骤
1.校验订单(校验订单状态,重复订单)
2.校验支付参数(不同的支付参数校验方式不同,例如,ApplePay/PayPal/GooglePay/微信/支付宝)
3.创建支付订单
4.获取支付路由
5.支付完成校验支付订单/支付凭证的状态
6.生成支付流水记录
7.请求订单系统,修改订单状态
以上步骤中,如果逻辑可以被划分为七个不同的模块,每个模块按顺序串联起来,上个模块执行完成后,交给下一个模块,因此适用于责任链模式
UML类图
public interface ContextHandler<PayContext> { /** * 处理输入的上下文数据 * * @param context 处理时的上下文数据 * @return 返回 true 则表示由下一个 ContextHandler 继续处理,返回 false 则表示处理结束 */ PayContext execute(PayContext context); }
@Slf4j @Component public class PayOrderCreatePipeline implements ContextHandler<PayContext> { @Override public PayContext execute(PayContext payContext) { //....业务逻辑,省略 return payContext } }
//责任链配置 @Configuration public class PipelineRouteConfig implements ApplicationContextAware { private ApplicationContext appContext; /** * 数据类型->管道中处理器类型列表 的路由 */ private static final Map<Class<PayContext>, List<Class<? extends ContextHandler<PayContext>>>> PIPELINE_ROUTE_MAP = new ConcurrentHashMap<>(4); /** * 在这里配置各种上下文类型对应的处理管道:键为上下文类型,值为处理器类型的列表 */ static { PIPELINE_ROUTE_MAP.put(PayContext.class, Arrays.asList( PayParamCheckPipeline.class, PaySpecialCheckPipeline.class, PayOrderCreatePipeline.class, PayChannelSurePipeline.class, PayRecordCreatePipeline.class, PayRoutePipeline.class, AfterPayPipeline.class //.....其他管道 )); } /** * 在 Spring 启动时,根据路由表生成对应的管道映射关系, * PipelineExecutor 从这里获取处理器列表 */ @Bean("routers") public Map<Class<PayContext>, List<? extends ContextHandler<PayContext>>> getHandlerPipelineMap() { return PIPELINE_ROUTE_MAP.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, this::toPipeline)); } /** * 根据给定的管道中 ContextHandler 的类型的列表,构建管道 */ private List<? extends ContextHandler<PayContext>> toPipeline( Map.Entry<Class<PayContext>, List<Class<? extends ContextHandler<PayContext>>>> entry) { return entry.getValue().stream().map(appContext::getBean).collect(Collectors.toList()); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { appContext = applicationContext; } }
//责任链客户端 @Slf4j @Component public class PipelineExecutor { @Resource private Map<Class<PayContext>, List<? extends ContextHandler<PayContext>>> routers; public PayContext execute(PayContext context) { Asserts.notNull(context, "参数上下文不能为空"); Class<? extends PayContext> clazz = context.getClass(); List<? extends ContextHandler<PayContext>> pipelines = routers.get(clazz); if (CollectionUtils.isEmpty(pipelines)) { log.info("==========>管道为空", clazz.getSimpleName()); throw new PayException(RetCode.ERROR); } PayContext _context = context; for (ContextHandler<PayContext> handler : pipelines) { _context = handler.execute(context); } return _context; } }
//请求参数上下文 //根据实际业务封装,用于在责任链之间传递 @Data @Builder @Accessors(chain = true) @AllArgsConstructor @NoArgsConstructor public class PayContext { /** * 支付请求参数 */ private OrderPayRequest orderPayRequest; /** * 订单信息 */ private OrderInfo orderInfo; /** * 支付记录 */ private PayRecordInfo payRecordInfo; /** * 通道支付信息 */ private ChannelInfo channelInfo; /** * APP信息 */ private AppInfo appInfo; /** * 渠道支付请求参数 */ private ChannelPayRequest channelPayRequest; /** * 渠道支付响应 */ private ChannelPayResponse channelPayResponse; /** * 支付响应VO */ private OrderPayVO orderPayVO; /** * 请求头 */ private HeaderServerInput header; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示