责任链模式是一种行为设计模式,允许将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。
问题分析
假如要开发一个在线订购系统,且希望对系统访问进行限制,只允许认证用户创建订单。此外,拥有管理权限的用户拥有所有订单的完全访问权限。
请求必须经过一系列依次检查后才能由订购系统来处理
在接下来的时间里,随着业务的需要,在现有基础上需要再添加几个检查步骤
代码变得越来越多,也越来越乱
每次新增功能都会使其更加臃肿,且在修改某个检查步骤有时会影响其他的检查步骤。最糟糕的是,当想要复用这些检查步骤来保护其他系统组件时,只能复制部分代码,因为这些组件只需部分而非全部的检查步骤。
系统会变得让人非常费解, 而且其维护成本也会激增。在艰难地和这些代码共处一段时间后,有一天终于决定对整个系统进行重构。
解决方案
责任链模式提供了高效、灵活的处理方案。处理者可以决定不再沿着链传递请求,这可高效地取消所有后续处理步骤。
在订购系统示例中,处理者会在进行请求处理工作后决定是否继续沿着链传递请求。如果请求中包含正确的数据,所有处理者都将执行自己的主要行为。
处理者依次排列,组成一条链
处理者接收到请求后可以自行决定是否能够对其进行处理。如果自己能够处理,处理者就不再继续传递请求。因此在这种情况下,每个请求要么最多有一个处理者对其进行处理,要么没有任何处理者对其进行处理。在处理图形用户界面元素栈中的事件时,这种方式非常常见
责任链模式既可以控制请求处理的顺序,又可以在不更改现有代码的情况下在程序中新增处理者。最重要的是处理者可以决定不再沿着链传递请求,这可高效地取消所有后续处理步骤。
通用轮子
基础设计
class Chain {
constructor() {
this.middleware = []
}
// 添加执行节点,也就是中间件
use(fn) {
if (typeof fn !== 'function') {
throw new TypeError('Middleware must be composed of functions!')
}
this.middleware.push(fn)
// 返回 this 让其可以链式调用
return this
}
// 接收上下文,并触发责任链执行
transmit(ctx) {
this.compose(this.middleware)(ctx)
}
}
核心方法
import compose from 'koa-compose'
使用示例
const chain = new Chain()
chain
.use(async (ctx, next) => {
console.log('1')
await next()
console.log('1')
})
.use(async (ctx, next) => {
console.log('2')
await next()
console.log('2')
})
.use(async (ctx, next) => {
console.log('3')
})
chain.transmit({ name: '传入执行链中的上下文' })