文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

面试官:说说你对责任链模式的理解?应用场景?

2024-12-02 15:56

关注

 一、是什么

责任链模式(Chain of Responsibility Pattern)就是某个请求需要多个对象进行处理,从而避免请求的发送者和接收之间的耦合关系

将这些对象连成一条链子,并沿着这条链子传递该请求,直到有对象处理它为止

职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递

常见的流程如下:

二、使用

假设我们负责一个售卖手机的网站,需求的定义是:需经过分别缴纳500元定金和200元定金的两轮预订,才能到正式购买阶段

公司对于交了定金的用户有一定的优惠政策,规则如下:

下面开始设计几个字段,解释它们的含义:

代码实现如下:

  1. const order = function (orderType, pay, stock) { 
  2.   if (orderType === 1) { 
  3.     if (pay === true) { 
  4.       console.log('500元定金预购,得到100元优惠券'
  5.     } else { 
  6.       if (stock > 0) { 
  7.         console.log('普通用户购买,无优惠券'
  8.       } else { 
  9.         console.log('手机库存不足'
  10.       } 
  11.     } else if (orderType === 2) { 
  12.       if (pay === true) { 
  13.         console.log('200元定金预购,得到50元优惠券'
  14.       } else { 
  15.         if (stock > 0) { 
  16.           console.log('普通用户购买,无优惠券'
  17.         } else { 
  18.           console.log('手机库存不足'
  19.         } 
  20.       } 
  21.     } else if (orderType === 3) { 
  22.       if (stock > 0) { 
  23.           console.log('普通用户购买,无优惠券'
  24.         } else { 
  25.           console.log('手机库存不足'
  26.       }  
  27.   } 
  28.  
  29. order(1, true, 500)  // 输出:500元定金预购,得到100元优惠券' 

可以看到上述代码大量实用化if...else,难以阅读,维护起来也很困难

如果进行优化,则可以把500元订单、200元订单以及普通购买拆分成三个函数,如下:

  1. function order500 (orderType, pay, stock) { 
  2.   if (orderType === 1 && pay === true) { 
  3.     console.log('500元定金预购,得到100元优惠券'
  4.   } else { 
  5.     order200(orderType, pay, stock) 
  6.   } 
  7.  
  8. function order200 (orderType, pay, stock) { 
  9.   if (orderType === 2 && pay === true) { 
  10.     console.log('200元定金预购,得到50元优惠券'
  11.   } else { 
  12.     order200(orderType, pay, stock) 
  13.   } 
  14.  
  15. function orderNormal (orderType, pay, stock) { 
  16.   if (stock > 0) { 
  17.     console.log('普通用户购买,无优惠券'
  18.   } else { 
  19.     console.log('手机库存不足'
  20.   } 
  21.  
  22. // 测试 
  23. order500(1, true, 500)  // 500元定金预购,得到100元优惠券 
  24. order500(1, false, 500)  // 普通用户购买,无优惠券 
  25. order500(2, true, 500)  // 200元定金预购,得到50元优惠券 
  26. order500(3, false, 500)  // 普通用户购买,无优惠券 
  27. order500(3, false, 0)   // 手机库存不足 

上述过程中,请求在链条中传递的顺序很僵硬,传递请求的代码跟业务代码耦合在一起,如果有一天要增加300元定金的预订,那么就要切断之前的链条,修改订单500函数的代码,重新在500和200之间加一根新的链条,这违反了开放-封闭原则

因此需要灵活更改责任链节点,如果不能处理的时候,则返回一个标识继续往后传递,如下:

  1. function order500 (orderType, pay, stock) { 
  2.   if (orderType === 1 && pay === true) { 
  3.     console.log('500元定金预购,得到100元优惠券'
  4.   } else { 
  5.     return 'nextSuccessor' 
  6.   } 
  7.  
  8. function order200 (orderType, pay, stock) { 
  9.   if (orderType === 2 && pay === true) { 
  10.     console.log('200元定金预购,得到50元优惠券'
  11.   } else { 
  12.     return 'nextSuccessor' 
  13.   } 
  14.  
  15. function orderNormal (orderType, pay, stock) { 
  16.   if (stock > 0) { 
  17.     console.log('普通用户购买,无优惠券'
  18.   } else { 
  19.     console.log('手机库存不足'
  20.   } 

下面再创建一个链类,将订单优惠函数传入链类中,如下:

  1. class Chain { 
  2.   construct (fn) { 
  3.     this.fn = fn 
  4.     this.successor = null 
  5.   } 
  6.  
  7.   setNextSuccessor (successor) { 
  8.     return this.successor = successor 
  9.   } 
  10.  
  11.   passRequest () { 
  12.     const res = this.fn.apply(this, arguments) 
  13.  
  14.     if (res === 'nextSuccessor') { 
  15.       return this.successor && this.successor.passRequest.apply(this.successor, arguments) 
  16.     } 
  17.     return res 
  18.   } 
  19.  
  20. // 包装三个订单函数 
  21. const chainOrder500 = new Chain(order500) 
  22. const chainOrder200 = new Chain(order200) 
  23. const chainOrderNormal = new Chain(orderNormal) 
  24.  
  25. // 指定节点在职责链中的位置 
  26. chainOrder500.setNextSuccessor(chainOrder200) 
  27. chainOrder200.setNextSuccessor(chainOrderNormal) 
  28.  
  29. // 最后把请求传递给第一个节点 
  30. chainOrder500.passRequest(1, true, 500)   // 500元定金预购,得到100元优惠券 
  31. chainOrder500.passRequest(2, true, 500)   // 200元定金预购,得到50元优惠券 
  32. chainOrder500.passRequest(3, true, 500)   // 普通用户购买,无优惠券 
  33. chainOrder500.passRequest(1, false, 0)    // 手机库存不足 

三、应用场景

责任链模式比较适合比如一个任务需要多个对象才能完成处理的情况或者代码存在许多if-else判断的情况,例如OA事件审批、分配开发任务等

在JavaScript中,无论是作用链、原型链,还是DOM节点中的事件冒泡,我们都能从中找到职责链的影子

使用了职责链模式之后,链中的节点对象可以灵活地拆分重组,增加、删除和修改节点在链中的位置都是很容易的事

参考文献

https://www.runoob.com/design-pattern/chain-of-responsibility-pattern.html

https://juejin.cn/post/6993948920929845279

https://juejin.cn/post/6844903855348514829

 

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯