Redian新闻
>
面试官问我什么是责任链模式,我把这篇文章甩给了他

面试官问我什么是责任链模式,我把这篇文章甩给了他

公众号新闻

点击上方“芋道源码”,选择“设为星标

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 10:33 更新文章,每天掉亿点点头发...

源码精品专栏

 
来源:Java知音

「什么是责任链」

责任链模式(Chain of Responsibility Pattern):责任链模式是⼀种对象的⾏为模式。

我们可以简单地理解为:当一个请求从执行开始到结束,需要经过很多层的处理,此时我们可以将这些不同层的处理给抽象出来,其中的每一层就是一个过滤链路,将它们窜起来之后,就会形成链状结构。如下图所示:

「为什么要这么设计,这样设计的好处在哪?」

「解耦:」 可以将每一层的逻辑都单独封装起来,互相不干预,达到解耦的效果。另外调用方也不必关心链路内部的那些handler都做了什么,链路内部的数据传递关系统一封装好。

「开闭原则:」 其实统一封装成多层之后,也满足了设计原则中的开闭原则,只需要新增或移开一项handler,就可以不影响其他层代码,直接改变原先责任链的逻辑。

「责任链模式有什么不足点?」

这里我归纳了下几个在实践中发现的不足点:

「链路长:」 请求必须要从链头出发,执行到链路末端,所以在链路的每一层中对于代码的性能需要谨慎考虑。

「排查困难:」 如果一旦任意一环出现了问题,要记得打好日志。

「长链路的业务代码就一定适合使用责任链模式吗?」

这里我先给出我的思考答案:不。我们来看看下边这个代码案例:

这是一段看起来非常长而且业务层次也很清晰的一段代码,如果我们将这段代码改成用责任链模式来实现,大概就是这样的。

这样看来代码变得简单了许多,调用方也确实不知道这里面处理了什么东西。但是这样的做法合适吗?

其实这里我们漏了一个步骤,那就是没有结合业务场景进行分析,过度设计地使用了责任链模式。

责任链模式,其实是比较适用于执行逻辑有先后顺序的场景,然后这里我所贴出来的代码其实有些方法是可以并行执行的,如果使用了责任链模式反而处理时间更长了些。

所以这里的代码 更好的做法应该是通过一个事件抛出 或者 是mq发送消息,去通知到各个业务服务进行相关操作。例如下边的代码所示:

/**
 * 会员升级处理
 *
 * @param currentLevel
 * @param role
 * @param userId
 * @param price
 * @param currentPrice
 */

public void upgradeV3(Integer currentLevel, int role, long userId, int price, int currentPrice) {
    //包装一些参数...
    mqTemplate.send(upgradeMsg);
}

「责任链的扩展思考」

「一链到底」

其实责任链的玩法有许多种,第一种 也是最经典的一种,从链路的开始执行到末尾。

这种链路我们的代码实现可以如下所示:

首先我们统一定义一个链路层的接口:

public interface BizFilterNode 
    //这个BizFilterContext是参数传递时候使用的上下文对象  
    void handle(BizFilterContext bizFilterContext);
}

然后就是如何遍历这批BizFilterNode对象

    public void filterHandle(BizFilterContext bizFilterContext) 
        for (BizFilterNode bizFilterNode : bizFilterNodes) {      
            bizFilterNode.handle(bizFilterContext);  
        } 
    }

直接一个for循环,然后对各层的链路节点遍历,执行相关的invoke方法。

「中途暂停」

中途暂停的意思是,链路执行到了一半,某一环节有问题,则整个脸路暂停了。例如下图所示:

这个时候,我们的代码可以这么来设计:

public interface BizFilterNode 
    void handle(BizFilterContext bizFilterContext)
    //增加一个是否终止执行后边逻辑    
    boolean terminateChain(BizFilterContext bizFilterContext);
}

然后还是在遍历的时候,进行判断处理

 public void filterHandle(BizFilterContext bizFilterContext) {   
     for (BizFilterNode bizFilterNode : bizFilterNodes) {     
     //全链路终止            
         if (bizFilterNode.terminateChain(bizFilterContext)) {                
             return;          
         }  
         bizFilterNode.handle(bizFilterContext);        
         }   
  }

「跳过当前环节」

所谓的跳过当前环节,其实意思是指当前的handler不想执行,直接跳到下一层的handler里面执行。

这个时候,我们只需要再在原有的代码里做写扩展就可以了:

public interface BizFilterNode {
    void handle(BizFilterContext bizFilterContext)

     boolean terminateChain(BizFilterContext bizFilterContext);  
     
     //是否跳过当前节点    
     boolean skipNode(BizFilterContext bizFilterContext);
     
     }

遍历节点的时候,进行逻辑判断处理

public void filterHandle(BizFilterContext bizFilterContext) {  
   for (BizFilterNode bizFilterNode : bizFilterNodes) {      
       if (bizFilterNode.terminateChain(bizFilterContext)) {                   
           return;         
       }         
       //判断是否要跳过当前环节    
       if (bizFilterNode.skipNode(bizFilterContext)) {     
           continue;       
       }            
           bizFilterNode.handle(bizFilterContext);   
       }   
}

「责任链模式在开源组件中的使用」

责任链在各个组件中应⽤很多,基本都⼤同⼩异。但是 Netty 的责任链相对来说有趣⼀些,我们⽤它来举

例简单介绍在netty中是如何使⽤责任链。 ChannelHandler 是 Netty 提供的默认处理者。核⼼的两个实现是 ChannelInboundHandler 和 ChannelOutboundHandler 。

  • ChannelInboundHandler:⼊站处理器,处理读数据的逻辑。
  • ChannelOutBoundHandler:出站处理器,处理写数据的逻辑。

当数据传递到netty的时候,会有一个读事件触发,接着会通过ChannelHandler里面的一个责任链。只不过Netty的责任链采用的是双向链路。这里的双向是指业务设计,并不是数据结构采用了双向链表。

ChannelInboundHandler里面有多个inbound节点,处理了不同的业务逻辑,而ChannelOutBoundHandler里面则有许多不同的outbound节点,也处理了不同的业务逻辑。

「小结」

责任链模式只是众多设计模式中的一种,合理的使用设计模式不一定会提升代码的性能,但是对于代码的维护性会有一定的帮助。在深入了解了它们的设计思想之后,希望可以对你平时的工作有所帮助。



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

已在知识星球更新源码解析如下:

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。

谢谢支持哟 (*^__^*)

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
日常两则CES 2023落幕,亮点都在这篇文章里了电解质水全网被抢断货?这篇文章告诉你到底有没有用。瞭望·治国理政纪事丨做好现代能源经济这篇文章从 ChatGPT 怎么念,到人们为啥害怕它,这篇文章都讲透!在这篇文章里,再快的人也只能停留三分钟。新西兰能成富国吗?人们能安居乐业吗?这篇文章真相了!IMF的这篇文章,很有意思!别再问我什么是黑胶不确定的世界里,树教给了我什么听说你今天想去参加纽约时代广场的跨年仪式,那你现在看这篇文章还来得及!该如何选择,这篇文章给你说清楚当你看到这篇文章,我们已离开地球表面只要5分钟,请为你的妈妈看完这篇文章!足球彩票怎么买才能赚钱?看完这篇文章再下注!这篇文章讲透了美国禁枪难背后的真正原因超级麻豆的《俄勒冈州行摄日记》这篇文章保你学通网络基础知识这篇文章,我们写了十年!(3000篇PPT制作教程,今天免费送!)为什么中国经济总能化危为机 人民日报这篇文章谈了5点情人节就要到了!千万别把这篇文章转给你男朋友…巧用『责任链模式』来优化 参数多重校验,非常优雅!慎终追远 信仰的颠覆(六十七)BQ干货 | 当面试官问“你更喜欢什么”时,你要这样说!孩子看见数学就头疼?那一定要看看这篇文章!发烧以后不能吃高蛋白,要吃清淡的?这篇文章告诉你真相COSTCO新发现和经常买的美味食物多彩班芙行(6)-步道的虐恋别被吃药顺序图误导了,这篇文章带你了解新冠用药真相如何培养学生的批判性思维和阅读分析能力?这篇文章告诉你!程序员面试反问面试官15道题,网友:到底谁在面试?为什么有人说不能吃兔兔?看完这篇文章,你就明白了什么样的生活方式能让你更有幸福感?这篇文章必读。面试官问我:一个 TCP 连接可以发多少个 HTTP 请求?我竟然回答不上来工业和信息化领域2022年主要数据,都在这篇文章里了
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。