最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 『面试的底气』—— 设计模式之职责链模式(二)|8月更文挑战

    正文概述 掘金(红尘炼心)   2021-08-21   401

    这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战

    前言

    在面试高级前端时,往往会遇到一些关于设计模式的问题,每次都回答不太理想。恰逢8月更文挑战的活动,准备用一个月时间好好理一下关于设计模式方面的知识点,给自己增加点面试的底气。

    在 上一篇简单实现了一个职责链模式,但是其中职责的传递非常僵硬,且违背了开放-封闭原则,故本文来介绍一种一种灵活可拆分的职责链节点的实现。

    解耦

    先来看一下之前设计的职责链节点。

    // 预缴1000定金
    const order1000 = (orderType, pay, stock) => {
      if (orderType === 1 && pay === true) {
        console.log('1000 元定金预购, 得到 500 优惠券');
      } else {
        order500(orderType, pay, stock); // 将请求传递给预缴1000定金订单
      }
    };
    // 预缴500定金
    const order500 = (orderType, pay, stock) =>{
      if (orderType === 2 && pay === true) {
        console.log('500 元定金预购, 得到 200 优惠券');
      } else {
        orderNormal(orderType, pay, stock); // 将请求传递给普通订单
      }
    };
    // 普通购买订单
    const orderNormal = (orderType, pay, stock) =>{
      if (stock > 0) {
        console.log('普通购买, 无优惠券');
      } else {
        console.log('手机库存不足');
      }
    };
    

    先将其解耦,怎么解耦呢,要做个约定,如果某个节点不能处理请求,则返回一个特定的字符串 toNextNode来表示该请求需要继续往后面的节点传递。

    // 预缴1000定金
    const order1000 = (orderType, pay, stock) => {
      if (orderType === 1 && pay === true) {
        console.log('1000 元定金预购, 得到 500 优惠券');
      } else {
        return 'toNextNode'; // 我不知道下一个节点是谁,反正把请求往后面传递
      }
    };
    // 预缴500定金
    const order500 = (orderType, pay, stock) =>{
      if (orderType === 2 && pay === true) {
        console.log('500 元定金预购, 得到 200 优惠券');
      } else {
        return 'toNextNode'; // 我不知道下一个节点是谁,反正把请求往后面传递
      }
    };
    // 普通购买订单
    const orderNormal = (orderType, pay, stock) =>{
      if (stock > 0) {
        console.log('普通购买, 无优惠券');
      } else {
        console.log('手机库存不足');
      }
    };
    

    组装职责链

    经过解耦,上面的每个函数都变成一个个普通函数,这里要创建一个包装函数来把普通函数包装成职责链节点。

    用一个类来作为包装函数,类中有方法,用来设置下个请求节点,还得有一个方法用来执行当前节点,且执行完后,若请求无法被处理,继续请求下个节点。

    class Chain{
      constructor(fn){
        this.fn = fn;
        this.nextNode = null;
      }
      setNextNode(fn){
        return this.nextNode = fn;
      }
      passRequest(){
        const res = this.fn.apply(this,arguments);
        if(res === 'toNextNode'){
          return this.nextNode && this.nextNode.passRequest.apply(this.nextNode, arguments);
        }
        return res;
      }
    }
    

    其中setNextNode方法设置下个请求节点,passRequest方法用来执行当前节点,且执行完后,若请求无法被处理,继续请求下个节点。

    现在把之前的三个函数包装成职责链节点:

    const chainOrder1000 = new Chain(order1000);
    const chainOrder500 = new Chain(order500);
    const chainOrderNormal = new Chain( orderNormal); 
    

    然后组装职责链节点成一条职责链:

    chainOrder1000.setNextNode( chainOrder500 );
    chainOrder500.setNextNode( chainOrderNormal ); 
    

    最后开始执行职责链:

    chainOrder1000.passRequest( 1, true, 500 ); // 输出:1000 元定金预购,得到 500 优惠券
    chainOrder1000.passRequest( 2, true, 500 ); // 输出:500 元定金预购,得到 200 优惠券
    chainOrder1000.passRequest( 3, true, 500 ); // 输出:普通购买,无优惠券
    chainOrder1000.passRequest( 1, false, 0 ); // 输出:手机库存不足
    

    拆卸职责链重新组装

    比如现在要新增一种的营销策略换成预缴300元定金,得50优惠券。可以这么处理。

    // 预缴300定金
    const order300 = (orderType, pay, stock) =>{
      if (orderType === 4 && pay === true) {
        console.log('300 元定金预购, 得到 50 优惠券');
      } else {
        return 'toNextNode'; // 我不知道下一个节点是谁,反正把请求往后面传递
      }
    };
    chainOrder300= new Chain(order300);
    chainOrder1000.setNextSuccessor(chainOrder500);
    chainOrder500.setNextSuccessor(chainOrder300);
    chainOrder300.setNextSuccessor(chainOrderNormal); 
    chainOrder1000.passRequest( 4, true, 500 );// 输出:300 元定金预购,得到 50 优惠券
    

    这样实现职责链,其职责链节点可以灵活拆卸。在变更职责链中节点顺序或新增职责链节点时,不会修改职责链节点的内容,遵循开放-封闭原则。

    异步的职责链节点如何实现

    上面介绍的职责链节点中都是同步返回一个特定的字符串 toNextNode来表示该请求需要继续往后面的节点传递。那如果职责链节点的请求是异步的呢,等异步请求返回的结果才能决定是否继续请求下一个职责链节点。那要如何实现?留个思考题,将在下篇文章中介绍。


    起源地下载网 » 『面试的底气』—— 设计模式之职责链模式(二)|8月更文挑战

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元