js设计模式【详解】—— 职责链模式

简介: js设计模式【详解】—— 职责链模式

职责链模式的定义

职责链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

职责链中的节点数量和顺序是可以自由变化的,我们可以在运行时决定链中包含哪些节点。

现实场景:公交上传递刷卡

使用场景:无论是作用域链、原型链、还是DOM节点中的事件冒泡,我们都能从中找到职责链的影子。

优点:解耦了请求发送者和N个接受者之间的复杂关系,可以手动指定起始节点

缺点:不能保证某个请求一定会被链中的节点处理

演示范例1 —— 职责链模式实现电商优惠劵发放

一个售卖手机的电商网站:针对预定用户实行优惠,支付过500元定金的用户会收到100元的商城优惠券,支付过200元定金的用户会收到50元的商城优惠券,没有支付定金的用户归为普通购买,且在库存有限的情况下不一定保证买到。


orderType:表示订单类型(定金用户或者普通购买用户),code的值为1的时候是500元定金用户,为2的时候是200元定金用户,为3的时候是普通购买用户。

pay:表示用户是否已经支付定金,值为true或者false,虽然用户已经下过500元定金的订单,但如果他一直没有支付定金,现在只能降级进入普通购买模式。

stock:表示当前用于普通购买的手机库存数量,已经支付过500元或者200元定金的用户不受此限制。

传统方式实现:

var order = function(orderType, isPaid, stock) {
  if(orderType === 1) {
    if(isPaid) {
      console.log("500元定金预购,得到100优惠券");
    } else {
      if(stock > 0) {
        console.log("普通购买,无优惠券");
      }else {
        console.log("库存不足");
      }
    }
  }else if(orderType === 2) {
    if(isPaid) {
      console.log("200元定金预购,得到50优惠券");
    } else {
      if(stock > 0) {
        console.log("普通购买,无优惠券");
      }else {
        console.log("库存不足");
      }
    }
  }else if(orderType === 3) {
    if(stock > 0) {
      console.log("普通购买,无优惠券");
    }else {
      console.log("库存不足");
    }
  }
}
order(1, true, 500);

职责链模式实现:

var order500 = function(orderType, isPaid, stock) {
  if(orderType === 1 && isPaid === true) {
    console.log("500元定金预购,得到100优惠券");
  }else {
    return "nextSuccessor";
  }
};
var order200 = function(orderType, isPaid, stock) {
  if(orderType === 2 && isPaid === true) {
    console.log("200元定金预购,得到50优惠券");
  }else {
    return "nextSuccessor";
  }
};
var orderNormal = function(orderType, isPaid, stock) {
  if(stock > 0) {
    console.log("普通购买,无优惠券");
  }else {
    console.log("库存不足");
  }
};
Function.prototype.after = function(fn) {
  var self = this;
  return function() {
    var ret = self.apply(this, arguments);
    if(ret === "nextSuccessor") {
      return fn.apply(this, arguments);
    }
    return ret;
  };
}
var order = order500.after(order200).after(orderNormal);
order(1, true, 10);

此处利用JavaScript的函数式特性改写了Function.prototype.after函数,虽然这种用AOP(面向切面编程)来实现职责链既简单又巧妙,但这种把函数叠在一起的方式,同时也叠加了函数的作用域,如果链条太长的话,也会对性能有较大的影响。

演示范例2 —— 职责链模式实现文件上传对象

// 是否支持flash
function supportFlash() {
    var hasFlash = 0; //是否安装了flash
    var flashVersion = 0; //flash版本
    if (document.all) {
        var swf = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
        if (swf) {
        hasFlash = 1;
          VSwf = swf.GetVariable("$version");
          flashVersion = parseInt(VSwf.split(" ")[1].split(",")[0]);
        }
    } else {
        if (navigator.plugins && navigator.plugins.length > 0) {
        var swf = navigator.plugins["Shockwave Flash"];
          if (swf) {
              hasFlash = 1;
              var words = swf.description.split(" ");
              for (var i = 0; i < words.length; ++i) {
                if (isNaN(parseInt(words[i]))) continue;
                flashVersion = parseInt(words[i]);
              }
          }
        }
    }
    return { f: hasFlash, v: flashVersion };
}
 
function getActiveUploadObj() {
  try{
    return new ActiveObject("TXFTNActiveX.FTNUpload");  // IE上传控件
  }catch(e) {
    return "nextSuccessor";
  }
}
function getFlashUploadObj() {
  if(supportFlash().f === 1) { 
    var str = '<object type="application/x-shockwave-flash"></object>';
    return $(str).appendTo($("body"));
  }
  return "nextSuccessor";
}
function getFormUploadObj() {
  var str = '<input name="file" type="file" class="ui-file" />';
  return $(str).appendTo($("body"));
}
 
Function.prototype.after = function(fn) {
  var self = this;
  return function() {
    var ret = self.apply(this, arguments);
    if(ret === "nextSuccessor") {
      return fn.apply(this, arguments);
    }
    return ret;
  };
}
var getUploadObj = getActiveUploadObj.after(getFlashUploadObj).after(getFormUploadObj);
console.log(getUploadObj());

可以和迭代器模式的文件上传进行对比  https://blog.csdn.net/weixin_41192489/article/details/116020037



更多设计模式详见——js设计模式【详解】总目录

https://blog.csdn.net/weixin_41192489/article/details/116154815

目录
相关文章
|
2天前
|
设计模式 JavaScript Go
js设计模式【详解】—— 状态模式
js设计模式【详解】—— 状态模式
17 7
|
2天前
|
设计模式 JavaScript 前端开发
js设计模式【详解】—— 组合模式
js设计模式【详解】—— 组合模式
20 7
|
2天前
|
设计模式 JavaScript
js设计模式【详解】—— 桥接模式
js设计模式【详解】—— 桥接模式
15 6
|
2天前
|
设计模式 JavaScript
js设计模式【详解】—— 原型模式
js设计模式【详解】—— 原型模式
14 6
|
2天前
|
设计模式 JavaScript 算法
js设计模式【详解】—— 模板方法模式
js设计模式【详解】—— 模板方法模式
17 6
|
2天前
|
设计模式 存储 JavaScript
js设计模式【详解】—— 享元模式
js设计模式【详解】—— 享元模式
16 6
|
2天前
|
设计模式 JavaScript API
js设计模式【详解】—— 命令模式
js设计模式【详解】—— 命令模式
16 6
|
2天前
|
设计模式 JavaScript 前端开发
js设计模式【详解】—— 构造函数模式
js设计模式【详解】—— 构造函数模式
14 6
|
2天前
|
设计模式 JavaScript
js设计模式【详解】—— 中介者模式
js设计模式【详解】—— 中介者模式
18 5
|
7天前
|
设计模式 存储 算法
设计模式学习心得之五种创建者模式(2)
设计模式学习心得之五种创建者模式(2)
12 2