责任链模式:构建高效灵活的处理系统

110 阅读3分钟

责任链模式是一种行为设计模式,允许将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。

chain-of-responsibility.png

问题分析

假如要开发一个在线订购系统,且希望对系统访问进行限制,只允许认证用户创建订单。此外,拥有管理权限的用户拥有所有订单的完全访问权限。

problem_1.png

请求必须经过一系列依次检查后才能由订购系统来处理

在接下来的时间里,随着业务的需要,在现有基础上需要再添加几个检查步骤

problem_2.png

代码变得越来越多,也越来越乱

每次新增功能都会使其更加臃肿,且在修改某个检查步骤有时会影响其他的检查步骤。最糟糕的是,当想要复用这些检查步骤来保护其他系统组件时,只能复制部分代码,因为这些组件只需部分而非全部的检查步骤。

系统会变得让人非常费解, 而且其维护成本也会激增。在艰难地和这些代码共处一段时间后,有一天终于决定对整个系统进行重构。

解决方案

责任链模式提供了高效、灵活的处理方案。处理者可以决定不再沿着链传递请求,这可高效地取消所有后续处理步骤。

在订购系统示例中,处理者会在进行请求处理工作后决定是否继续沿着链传递请求。如果请求中包含正确的数据,所有处理者都将执行自己的主要行为。

solution.png

处理者依次排列,组成一条链

处理者接收到请求后可以自行决定是否能够对其进行处理。如果自己能够处理,处理者就不再继续传递请求。因此在这种情况下,每个请求要么最多有一个处理者对其进行处理,要么没有任何处理者对其进行处理。在处理图形用户界面元素栈中的事件时,这种方式非常常见

solution_gui.png

责任链模式既可以控制请求处理的顺序,又可以在不更改现有代码的情况下在程序中新增处理者。最重要的是处理者可以决定不再沿着链传递请求,这可高效地取消所有后续处理步骤。

通用轮子

基础设计

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: '传入执行链中的上下文' })