职责链模式

2018-07-06  本文已影响0人  bby365

处理请求的对象被连接成一条链,发送者不知道接收是谁,弱化两者之间的强联系。
场景:乘坐公交车刷卡

  1. 一般代码
    使用if-else语句,缺点:分支过多,后期维护困难。
  2. 优化一
    将每一种情况,单独写成一个函数,如果处理不了,指定下一个处理函数去处理。
var order500 = function( orderType, pay, stock ){
    if ( orderType === 1 && pay === true ){
        console.log( '500 元定金预购, 得到100 优惠券' );
    }else{
        order200( orderType, pay, stock ); // 将请求传递给200 元订单
    }

};

这样,每次都从order500开始,一直往下传递,直到被处理。
缺点:每个函数都要指定特定的下一个处理函数,这样的话,顺序固定,太僵硬。

  1. 优化2
    每个处理函数,不再指定特定的处理函数,只是返回一个固定的标识符。
    然后创建一个构造函数chain ,具有2个原型方法:指定下一个节点 和 传递请求。
// 1. 不会指定下一个节点,返回一个标识符,增加灵活性。
var order500 = function( orderType, pay, stock ){
    if ( orderType === 1 && pay === true ){
        console.log( '500 元定金预购,得到100 优惠券' );
    }else{
        return 'nextSuccessor'; // 我不知道下一个节点是谁,反正把请求往后面传递
    }
};
// 2. 创建Chain构造函数,包括2个原型方法。
// Chain.prototype.setNextSuccessor 指定在链中的下一个节点
// Chain.prototype.passRequest 传递请求给某个节点
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 === 'nextSuccessor' ){
        return this.successor && this.successor.passRequest.apply( this.successor, arguments );
    }
    return ret;
};
//  3-1 包装成职责链的节点
var chainOrder500 = new Chain( order500 );
var chainOrder200 = new Chain( order200 );
var chainOrderNormal = new Chain( orderNormal );

// 3-2 指定下一个节点
chainOrder500.setNextSuccessor( chainOrder200 );
chainOrder200.setNextSuccessor( chainOrderNormal );

// 3-3 请求从第一个节点开始,处理不了,向后传递
chainOrder500.passRequest( 3, true, 500 ); // 输出:普通购买,无优惠券

优点:

  1. 可以自由的组合,指定请求传递顺序。
  2. 有新的需求,添加也很简单,调用setNextSuccessor()可以轻松插入到指定位置。

模拟异步请求例子

 var fn1 = new Chain(function(){
     console.log(1)
     return 'nextSuccessor'
 })
 var fn2 = new Chain(function(){
     console.log(2)
     var self = this;
     setTimeout(function(){
        return 'nextSuccessor'
     },2000)
    
 })
 var fn3 = new Chain(function(){
     console.log(3)
 })
fn1.setNextSuccessor(fn2).setNextSuccessor(fn3)
console.log(fn1.passRequest())

// 结果:1,2,undefined

分析:

  1. fn2 中有个异步方法,fn2.passRequest()返回的是undefined ,异步方法中的返回值没有作用。
  2. 如果想要执行fn3,那么fn2中的异步方法要调用一个原型方法去将请求传递给fn3
  3. 上述的方法都放到原型上是因为这些方法是公用的,每一个节点都可能调用。

改进:

// 增加一个原型方法
Chain.prototype.next = function(){
    return this.successor && this.successor.passRequest.apply( this.successor, arguments );
};

 var fn1 = new Chain(function(){
     console.log(1)
     return 'nextSuccessor'
 })
 var fn2 = new Chain(function(){
     console.log(2)
     var self = this;
    //  节点有权利决定什么时候把请求交给下一个节点
     setTimeout(function(){
        self.next()
     },2000)
    
 })
 var fn3 = new Chain(function(){
     console.log(3)
 })

fn1.setNextSuccessor(fn2).setNextSuccessor(fn3)
console.log(fn1.passRequest())
上一篇下一篇

猜你喜欢

热点阅读