设计模式-看了就会的职责链模式(六)

这是我参与更文挑战的第4天,活动详情查看: 更文挑战javascript

1、什么是职责链模式

职责链模式就是当一个对象 a,有多种可能的请求对象 bcde 时,咱们为 bcde 分别定义一个职责,组成一条职责链,这样 a 只须要找到 b 发起请求,而后沿着职责链继续请求,直到找到一个对象来处理 ajava

女孩子们都喜欢结伴吃饭,我如今要找一我的一块儿吃饭,代码以下:git

嗯.....女程序员确实是这样,吃个饭也要写代码发请求的。程序员

const [ astrid, brooke, calliope ] = [{
    name: 'astrid',
    requirement: '我要吃湘菜'
},{
    name: 'brooke',
    requirement: '我要找10我的一块儿吃饭'
},{
    name: 'calliope',
    requirement: '我要和男友一块儿吃饭'
}]

// 是否知足Astrid的要求
function isSatisfyAstrid (user) { 
    // ... 省略... 
}

// 是否知足Brooke的要求
function isSatisfyBrooke (user) { 
    // ... 省略... 
}

// 是否知足Calliope的要求
function isSatisfyCalliope (user) { 
    // ... 省略... 
}

function eatDinner () {
    if (isSatisfyAstrid()) {
        console.log(`我能够和 astrid 一块儿吃晚饭啦`)
    } else if (isSatisfyBrooke()) {
        console.log(`我能够和 brooke 一块儿吃晚饭啦`)
    } else if (isSatisfyCalliope()) {
        console.log(`我能够和 calliope 一块儿吃晚饭啦`)
    } else {
        console.log(`哎呀,我要一我的吃晚饭啦`)
    }
}
复制代码

因为 astridbrookecalliope 吃晚饭的要求不一样,我须要一个个去发起晚餐请求,直到找到答应和我一块儿吃晚饭的人。github

在这里,我假设 astrid 的要求是要吃湘菜,brooke 的要求是要找 10 我的凑一桌一块儿吃,calliope 的要求是只想和男友一块儿吃饭。web

上述代码用 if-else 的作法很是死板,假如我又多了个朋友 davi,我必须再次修改 eatDinner 方法,违反了开放-封闭原则,不易于维护。设计模式

下面使用职责链来优化上述代码,代码以下:markdown

// 给每一个人定义一个职责
const chainOrderA = new Chain(isSatisfyAstrid)
const chainOrderB = new Chain(isSatisfyBrooke)
const chainOrderC = new Chain(isSatisfyCalliope)

// 设置一下职责链的顺序
chainOrderA.setNextSuccessor(chainOrderB)
chainOrderB.setNextSuccessor(chainOrderC)

// 发起请求,这时我只须要向职责链上的第一我的请求
function eatDinner () {
    chainOrder.passRequest() // 发起请求
}
复制代码

将职责做为转入 Chain 函数,并经过 setNextSuccessor 定义该职责的下一个职责函数,组成一条 chainOrderA -> chainOrderB -> chainOrderC 职责链,这时,我只须要向 astrid 发起请求,若是请求失败,将会沿着职责链继续请求,直到找到和我一块儿吃晚饭的人。app

下面将讲述在实际场景中怎么使用职责链模式,怎么实现 Chain 方法,请继续往下看。函数

2、实际场景

1. 618 预售商品订单

下周就是 618,电商网站免不得会推出商品预售活动,假设在 618 以前,预付 500 定金,可得到 100 元优惠券,预付 200 元定金,可得到 50 优惠券,未付定金则无优惠券。618 当天的购买事件以下:

1.1 普通作法

先上代码。

本文代码仅举例说明,和业务无关。

const order = function (orderType) {
    if (orderType === 500) {
        console.log('已预付500定金,享有100优惠券')
    } else if (orderType === 200) {
        console.log('已预付200定金,享有50元优惠券')
    } else {
        console.log('未付定金,无优惠')
    }
}

order(500) // '已预付500定金,享有100优惠券'
复制代码

熟悉的代码,一长段的 if-else 判断,不利于维护。

1.2 职责链模式

定义一个职责类 Chain

  • 接收一个职责函数 fn 做为参数;
  • setNextSuccessor 指定该职责的下一个职责函数;
  • passRequest 发起对职责函数 fn 的请求;
    • 若是返回结果是nextSuccesstor,说明请求失败,继续请求职责链上的下一个职责函数;
    • 若是不是返回 nextSuccesstor,说明找到了接收请求的对象,返回请求结果,再也不继续执行职责链上的下一个职责函数。

代码以下:

const Chain = function(fn) {
  this.fn = fn;
  this.successor = null;
};

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

Chain.prototype.passRequest = function() {
  const ret = this.fn.apply(this, arguments)
  if (ret === 'nextSuccessor') {
    return this.successor && this.successor.passRequest.apply(this.successor, arguments);
  }
  return ret;
};
复制代码

而后定义职责类实例,经过 setNextSuccessor 组成职责链,代码以下:

const order500 = function (orderType) {
  if (orderType === 500) {
      console.log('已预付500定金,享有100优惠券')
  } else {
    return 'nextSuccessor'
  }
} 

const order200 = function (orderType) {
  if (orderType === 200) {
    console.log('已预付200定金,享有50元优惠券')
  } else {
    return 'nextSuccessor'
  }
} 

const chainOrder500 = new Chain(order500)

const chainOrder200 = new Chain(order200)

chainOrder500.setNextSuccessor(chainOrder200)

chainOrder500.passRequest(200)
复制代码

上述代码将 chainOrder500chainOrder200 组成一条职责链,无论用户是哪一种类型,都只须要向 chainOrder500 发起请求,若是 chainOrder500 没法处理请求,就会继续沿着职责链发起请求,直到找到能处理请求的职责方法。

经过职责链模式,解耦了请求发送者和多个接收者之间的复杂关系,再也不须要知道具体哪一个接收者来接收发送的请求,只须要向职责链的第一个阶段发起请求。

3、小结

职责链模式,帮助咱们管理代码,下降发起请求和接收请求对象之间的耦合。

职责链模式中的节点数量和顺序是能够自由变更的,能够在运行时决定链中包含哪些节点。

可经过 github源码 进行实操练习。

但愿能对你有所帮助,感谢阅读~别忘了点个赞鼓励一下我哦,笔芯❤️


· 往期精彩 ·

【设计模式-谁没碰见过几个单例模式(一)】

【设计模式-什么是快乐星球,什么是策略模式(二)】

【设计模式-原来这就是代理模式(三)】

【设计模式-简单易懂的观察者模式(四)】

【设计模式-不会吧,不会还有人不知道装饰器模式吧(五)】

【设计模式-看了就会的职责链模式(六)】

相关文章
相关标签/搜索