javaScript设计模式之职责链模式

介绍

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

实例引入

<span style="font-size:14px;">var order = function( orderType, pay, stock ){
		if ( orderType === 1 ){ // 500 元定金购买模式
			if ( pay === true ){ // 已支付定金
				console.log( '500 元定金预购, 得到100 优惠券' );
			}else{ // 未支付定金,降级到普通购买模式
				if ( stock > 0 ){ // 用于普通购买的手机还有库存
					console.log( '普通购买, 无优惠券' );

				}else{
					console.log( '手机库存不足' );
				}
			}
		}
		else if ( orderType === 2 ){ // 200 元定金购买模式
			if ( pay === true ){
				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); // 输出: 500 元定金预购, 得到100 优惠券</span>
上述方法 order函数 不仅巨大而且难以阅读,下面采用职责链重构这段代码。

var order500 = function( orderType, pay, stock ){
		if ( orderType === 1 && pay === true ){
			console.log( '500 元定金预购, 得到100 优惠券' );
		}else{
			order200( orderType, pay, stock ); // 将请求传递给200 元订单
		}

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

	// 测试结果:
	order500( 1 , true, 500); // 输出:500 元定金预购, 得到100 优惠券
	order500( 1, false, 500 ); // 输出:普通购买, 无优惠券
	order500( 2, true, 500 ); // 输出:200 元定金预购, 得到500 优惠券
	order500( 3, false, 500 ); // 输出:普通购买, 无优惠券
	order500( 3, false, 0 ); // 输出:手机库存不足

可以看到重构的代码已经非常清晰了,其中把一个大函数分了3个小函数,并且去掉了许多嵌套的条件分支语句。但是也可以看到,请求在链条中的顺序非常僵硬,传递请求的代码

order200( orderType, pay, stock ); // 将请求传递给200 元订单
orderNormal( orderType, pay, stock ); // 将请求传递给普通订单
被耦合在业务函数中,这依然违反了开放封闭的原则。采用一种改进的灵活可拆分的职责链节点对链中的各个节点灵活的拆分和重组:如果节点不能处理请求,则返回一个特定的字符串“nextSuccessor”来表示请求需要继续往后面传递。

<span style="font-size:14px;">var order500 = function( orderType, pay, stock ){
		if ( orderType === 1 && pay === true ){
			console.log( '500 元定金预购,得到100 优惠券' );
		}else{
			return 'nextSuccessor'; // 我不知道下一个节点是谁,反正把请求往后面传递
		}
	};

	var order200 = function( orderType, pay, stock ){
		if ( orderType === 2 && pay === true ){
			console.log( '200 元定金预购,得到50 优惠券' );
		}else{
			return 'nextSuccessor'; // 我不知道下一个节点是谁,反正把请求往后面传递
		}
	};

	var orderNormal = function( orderType, pay, stock ){
		if ( stock > 0 ){
			console.log( '普通购买,无优惠券' );
		}else{
			console.log( '手机库存不足' );
		}
	};

	// Chain.prototype.setNextSuccessor 指定在链中的下一个节点
	// Chain.prototype.passRequest 传递请求给某个节点
	var Chain = function( fn ){    //fn即为要包装的函数
		this.fn = fn;
		this.successor = null;  //实例属性表示下一个节点
	};

	Chain.prototype.setNextSuccessor = function( successor ){
		return this.successor = successor;
	};

	Chain.prototype.passRequest = function(){

		var ret = this.fn.apply( this, arguments );
		if ( ret === 'nextSuccessor' ){
			return this.successor && this.successor.passRequest.apply( this.successor, arguments );
		}
		return ret;
	};

	var chainOrder500 = new Chain( order500 );
	var chainOrder200 = new Chain( order200 );
	var chainOrderNormal = new Chain( orderNormal );

	chainOrder500.setNextSuccessor( chainOrder200 );
	chainOrder200.setNextSuccessor( chainOrderNormal );
	chainOrder500.passRequest( 1, true, 500 ); // 输出:500 元定金预购,得到100 优惠券
	chainOrder500.passRequest( 2, true, 500 ); // 输出:200 元定金预购,得到50 优惠券
	chainOrder500.passRequest( 3, true, 500 ); // 输出:普通购买,无优惠券
	chainOrder500.passRequest( 1, false, 0 ); // 输出:手机库存不足
/*
       简化后:
       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 = order500yuan.after( order200yuan ).after( orderNormal );
	order( 1, true, 500 ); // 输出:500 元定金预购,得到100 优惠券
	order( 2, true, 500 ); // 输出:200 元定金预购,得到50 优惠券
	order( 1, false, 500 ); // 输出:普通购买,无优惠券
</span><pre name="code" class="javascript"><span style="font-size:14px;">*/</span>
 
 

总结职责链模式的模式的优缺点

很明显采用职责链模式以后,链中的节点对象可以灵活的拆分重组;可以手动指定起始节点,请求并不一定是从链中的第一个节点开始传递。

实际上只要运用得当,职责链模式可以很好的帮助我们管理代码,降低发起请求的对象和处理请求的对象之间的耦合性。职责链中的人节点数量和顺序是可以自由变化的,我们可以在运行时决定链中包含哪些节点。      








猜你喜欢

转载自blog.csdn.net/shoushou71/article/details/51746566
今日推荐