# 设计模式:职责链模式
# 什么是职责链模式
传送快递
举一个生活中的例子:我们知道快递公司有很多中转站。用来传递那些没有到目的地需要继续托运的快递。假如一个从海南到上海的的快递需要沿途经过4次中转的话那么就需要四次条件判断
let box = { name: '海南特产包裹', targetCity: '上海' }
// 海南 中转站
if (box.targetCity === '海南') {
// 深圳 中转站
} else if (box.targetCity === '深圳') {
// 广州 中转站
} else if (box.targetCity === '广州') {
// 上海 中转站
} else if (box.targetCity === '上海') {
console.log('到达目的地')
}
这样的代码显然太臭了,可维护性很差。我们来看看如何用职责链模式来修改它。
# Coding
同步职责链
const Enum = {
nextSuccessor: 'nextSuccessor',
ShangHai: '上海',
GuangZhou: '广州',
ShenZhen: '深圳',
HaiNan: '海南',
}
// 包裹
let box = { name: '海南特产包裹', targetCity: '上海' }
// 上海 中转站
let ShangHaiTransfer = function(box) {
if (box.targetCity === Enum.ShangHai) {
console.log('上海收到')
return null
} else {
return Enum.nextSuccessor
}
}
// 广州 中转站
let GuangZhouTransfer = function(box) {
if (box.targetCity === Enum.GuangZhou) {
console.log('广州收到')
return null
} else {
return Enum.nextSuccessor
}
}
// 深圳 中转站
let ShenZhenTransfer = function(box) {
if (box.targetCity === Enum.ShenZhen) {
console.log('深圳收到')
return null
} else {
return Enum.nextSuccessor
}
}
// 海南 中转站
let HaiNanTransfer = function(box) {
if (box.targetCity === Enum.HaiNan) {
console.log('海南收到')
return null
} else {
return Enum.nextSuccessor
}
}
// ------------------------------------------------
// 同步职责链
let Chain = function(transfer, fn) {
this.transfer = transfer
this.fn = fn
this.successor = null
}
Chain.prototype.setNextSuccessor = function(successor) {
this.successor = successor
}
Chain.prototype.passRequest = function() {
var ret = this.fn.apply(this, arguments);
if (ret === Enum.nextSuccessor) {
console.log(this.transfer, '递交下一个关卡')
if (this.successor) {
ret = this.successor.passRequest.apply(this.successor, arguments)
}
}
return ret;
}
// 定义职责对象
var shanghai = new Chain(Enum.ShangHai, ShangHaiTransfer);
var guangzhou = new Chain(Enum.GuangZhou, GuangZhouTransfer);
var shenzhen = new Chain(Enum.ShenZhen, ShenZhenTransfer);
var hainan = new Chain(Enum.HaiNan, HaiNanTransfer);
// 关联成一条职责链
hainan.setNextSuccessor(shenzhen)
shenzhen.setNextSuccessor(guangzhou)
guangzhou.setNextSuccessor(shanghai)
// 发生包裹
hainan.passRequest(box)
职责链有个好处是,你可以随意搭配条件判断的顺序。即便是需求变更,需要你从中增加条件也是很便捷的事情。
异步职责链
有些时候,我们的判断条件需要请求接口。这时职责链要暂停,等待接口返回。我们来修改一下 Chain 类,让其支持这种情况。
首先要增加一个 next 方法,并且在 passRequest 之前保存一次参数列表
Chain.prototype.passRequest = function() {
this.param = arguments
var ret = this.fn.apply(this, arguments);
return ret;
}
Chain.prototype.next = function () {
console.log(this.transfer, '递交下一个关卡')
if (this.successor) {
this.successor.passRequest.apply(this.successor, this.param)
}
}
在条件函数中显示的调用 this.next() 函数。
// 上海 中转站
let ShangHaiTransfer = function(box) {
if (box.targetCity === Enum.ShangHai) {
console.log('上海收到')
} else {
this.next()
}
}
// ...
// 深圳 中转站
let ShenZhenTransfer = function(box) {
if (box.targetCity === Enum.ShenZhen) {
console.log('深圳收到', this)
} else {
// 模拟异步操作
setTimeout(() => {
this.next()
}, 2000)
}
}
这样就为我们的职责链增加了异步功能。
# 总结
职责链在面对复杂系统中可以有效的降低对象之间的耦合性。另外职责链中的每一个节点都可以灵活配置。
← 设计模式:享元模式 设计模式:中介者模式 →