JavaScript设计模式_10_职责链模式
职责链模式的定义是:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。职责链模式的名字非常形象,一系列可能会处理请求的对象被连接成一条链,请求在这些对象之间依次传递,直到遇到一个可以处理它的对象,我们把这些对象称为链中的节点。
如下图所示:
/** * pre:职责链模式 * 定义:一系列可能处理请求的对象链接成一条链, * 请求在这条链中传递,直到遇到一个可以处理它的对象。 */ // --------- 示例 1 ----------- /** * 某品牌手机销售,交500元定金可得100元电商优惠券,交300元可得50元优惠券, * 没有交定金的用户只能进行普通购买,而且还不一定能买的到。 * 将这一过程用代码写出来: * orderType: 1,交500定金;2,交300元定金,3,普通购买 * pay:true 已支付定金,false未支付定金 * stock:手机库存数 */ var order = (function() { var favorCache = { // 优惠配置 1: [500, 100], 2: [300, 50] }; var normal = function(stock) { // 普通购买 if(stock > 0) { console.log("普通购买.库存数:" + stock); } else { console.log("库存不足."); } }; var preOrder = function(orderType, pay) { // 预付定金 if(orderType in favorCache && pay) { console.log("支付定金:" + favorCache[orderType][0] + ",获得" + favorCache[orderType][1] + "元优惠券."); return true; } return false; }; return function(orderType, pay, stock) { preOrder(orderType, pay) || normal(stock); } })(); order(1, true, 500); order(1, false, 500); order(2, true, 200); order(3, false, 100); order(3, false, 0); // ------------- 示例2 -------------- /* * 使用职责链模式实现功能 */ var order500 = function(orderType, pay, stock) { if(orderType === 1 && pay) { console.log("支付定金:500元,获得100元优惠券."); } else { order300(orderType, pay, stock); } }; var order300 = function(orderType, pay, stock) { if(orderType === 2 && pay) { console.log("支付定金:300元,获得50元优惠券."); } else { orderNormal(orderType, pay, stock); } }; var orderNormal = function(orderType, pay, stock) { if(stock > 0) { console.log("普通购买.库存数:" + stock); } else { console.log("库存不足."); } }; order500(1, true, 500); order500(1, false, 500); order500(2, true, 200); order500(3, false, 100); order500(3, false, 0); /** * 不足:虽然把函数拆分成互不影响的3个小函数,但是传递请求的代码被耦合在业务函数之中, * 这样的请求传递非常的僵硬,也违背了开放-封闭原则。 */ //--------------- 示例3 ------------- /** * 改进上面的职责链模式,让每个节点可以单独拆分和重组. */ var order500 = function(orderType, pay, stock) { if(orderType === 1 && pay) { console.log("支付定金:500元,获得100元优惠券."); } else { return "next"; } }; var order300 = function(orderType, pay, stock) { if(orderType === 2 && pay) { console.log("支付定金:300元,获得50元优惠券."); } else { return "next"; } }; var orderNormal = function(orderType, pay, stock) { if(stock > 0) { console.log("普通购买.库存数:" + stock); } else { console.log("库存不足."); } }; // -- 定义链节点函数 -- var Chain = function(fn) { this.fn = fn; this.next = null; }; Chain.prototype.setNext = function(next) { this.next = next; }; Chain.prototype.passRequest = function() { var result = this.fn.apply(this, arguments); if("next" === result) { return this.next && this.next.passRequest.apply(this.next, arguments); } return result; }; var chain500 = new Chain(order500); var chain300 = new Chain(order300); var chainNormal = new Chain(orderNormal); chain500.setNext(chain300); chain300.setNext(chainNormal); chain500.passRequest(1, true, 500); chain500.passRequest(1, false, 500); chain500.passRequest(2, true, 200); chain500.passRequest(3, false, 100); chain500.passRequest(3, false, 0); //---------- 示例4 ----------- /** * 上个示例中,已经实现了一个职责链模式,但在现实中,我们往往是 * 根据一个异步请求的结果,来决定是否执行下一个函数。 */ var Chain = function(fn) { this.fn = fn; this.next = null; }; Chain.prototype.setNext = function(next) { // 设置下一个执行函数 return this.next = next; }; Chain.prototype.passRequest = function() { // 传递请求 var result = this.fn.apply(this, arguments); if("next" === result) { return this.next && this.next.passRequest.apply(this.next, arguments); } return result; }; Chain.prototype.executeNext = function() { // 主动执行下一个函数 return this.next && this.next.passRequest.apply(this.next, arguments); }; var fn1 = new Chain(function() { console.log(1); return "next"; }); var fn2 = new Chain(function() { console.log(2); var self = this; setTimeout(function() { self.executeNext(); }, 2000); // 模拟异步回调 }); var fn3 = new Chain(function() { console.log(3); }); fn1.setNext(fn2).setNext(fn3); fn1.passRequest(); /** * 经过这些例子,我们总结一下职责链模式的优缺点: * 优点: * 1、各个处理函数互不影响,各自独立; * 2、删除、增加节点比较灵活,不需要改动其他函数的代码; * 3、可以手动指定起始节点。比如手机商城的例子,付过定金的订单全部结束购买流程后, * 完全可以把请求交给普通订单处理:orderNormal(1,false,500); * 缺点: * 1、我们不能保证某个请求一定会被职责链中的节点处理; * 2、某些请求被处理时,可能会经历多个节点,会给系统带来性能损耗。 */ // ----------- 示例5 -------------- /** * 利用js函数式的特性,创建职责链 */ Function.prototype.after = function(fn) { var self = this; return function() { var result = self.apply(this, arguments); if("next" === result) { return fn.apply(this, arguments); } return result; } }; var fn1 = function() { console.log(1); return "next"; }; var fn2 = function() { console.log(2); return "next"; }; var fn3 = function() { console.log(3); }; var ff = fn1.after(fn2).after(fn3); ff();
作者:『Stinchan』
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。