javascript职责链模式
职责连模式的定义是:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,知道有一个对象处理它为止。
实例:公司针对支付过定金的用户有一定的优惠政策。在正式购买后,已经支付过500员定金的用户会收到100员的商城优惠券,200定金的用户可以收到50元的优惠券,没有支付定金的用户没有优惠券,且在库存有限的情况下不一定保证能买到。流程如下:
var order = function( orderType, pay, stock){
if( orderType === 1 ){
if( pay === true ){
console.log( "500元定金预购,得到100优惠券" );
}else{
if( stock > 0 ){
console.log( "普通购买,无优惠券" );
}else{
console.log( "手机库存不足" );
}
}
}else if( orderType === 2 ){
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优惠券
虽然上面的代码能完成给定的任务,但却不是值得夸奖的代码。order函数不仅可读性差,而且需要经常进行修改。
用职责链模式重构代码:
//500元订单
var order500 = function( orderType, pay, stock ){
if( orderType === 1 && pay === true){
console.log( "500元定金预购,得到100优惠券" );
}else{
order200( orderType, pay, stock );
}
}
//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优惠券
可以看出,执行结果和前面的order函数一样,但代码的结构已经清晰了很多,我们把一个大函数分拆成3个小函数,去掉了许多条件分支语句。
但是,应该注意到的是请求在链条传递中的顺序非常僵硬,传递请求的代码呗耦合在了业务函数中。
var order500 = function( orderType, pay, stock ){
if( orderType === 1 && pay === true){
console.log( "500元定金预购,得到100优惠券" );
}else{
order200( orderType, pay, stock ); // order500和order200耦合在一起了
}
}
这依然是违反开放-封闭原则的,如果有天姚增加300元预定或者去掉200元预定,那么就意味着必须改动这些业务函数内部。
灵活可拆分的职责链节点:
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( "手机库存不足" );
}
}
接下来把函数包装进职责链节点:
var Chain = function( 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 === 'nestSuccessor' ){
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( orderNormal );
chainOrder500.passRequest( 1, true, 500 ); // 输出:500元定金预购,得到100优惠券
chainOrder500.passRequest( 2, true, 500 ); // 输出:200元定金预购,得到50优惠券
chainOrder500.passRequest( 3, true, 500 ); // 输出:普通购买,无优惠券
chainOrder500.passRequest( 1, false, 0 ); // 输出:手机库存不足
现在的代码灵活多了。