您现在的位置是:网站首页 > 责任链模式(Chain of Responsibility)的请求处理流程文章详情

责任链模式(Chain of Responsibility)的请求处理流程

责任链模式的基本概念

责任链模式是一种行为设计模式,允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下一个处理者。这种模式解耦了请求的发送者和接收者,使得多个对象都有机会处理请求。

在JavaScript中,责任链模式通常表现为一个对象包含对另一个对象的引用,形成一条链。当请求到达某个对象时,这个对象要么处理它,要么将其传递给链中的下一个对象。

责任链模式的结构

典型的责任链模式包含以下几个关键组成部分:

  1. Handler(处理者):定义处理请求的接口,通常包含一个方法来设置下一个处理者,以及一个方法来处理请求。
  2. ConcreteHandler(具体处理者):实现处理请求的具体逻辑,决定是否处理请求以及是否将请求传递给下一个处理者。
  3. Client(客户端):创建处理链,并向链上的第一个处理者提交请求。
class Handler {
  constructor() {
    this.nextHandler = null;
  }

  setNext(handler) {
    this.nextHandler = handler;
    return handler;
  }

  handle(request) {
    if (this.nextHandler) {
      return this.nextHandler.handle(request);
    }
    return null;
  }
}

class ConcreteHandlerA extends Handler {
  handle(request) {
    if (request === 'A') {
      return `HandlerA处理了请求: ${request}`;
    }
    return super.handle(request);
  }
}

class ConcreteHandlerB extends Handler {
  handle(request) {
    if (request === 'B') {
      return `HandlerB处理了请求: ${request}`;
    }
    return super.handle(request);
  }
}

// 使用示例
const handlerA = new ConcreteHandlerA();
const handlerB = new ConcreteHandlerB();

handlerA.setNext(handlerB);

console.log(handlerA.handle('A')); // HandlerA处理了请求: A
console.log(handlerA.handle('B')); // HandlerB处理了请求: B
console.log(handlerA.handle('C')); // null

责任链模式的应用场景

责任链模式特别适用于以下场景:

  1. 多级审批流程:如请假审批,不同级别的领导有不同的审批权限。
  2. 事件冒泡机制:DOM事件处理就是典型的责任链模式实现。
  3. 中间件管道:Express/Koa等框架的中间件机制。
  4. 错误处理:尝试多个错误处理器直到找到合适的处理方式。

JavaScript中的实际应用示例

1. DOM事件处理

浏览器中的事件冒泡机制就是责任链模式的典型应用。事件从最具体的元素开始,逐级向上传播到document对象。

document.getElementById('child').addEventListener('click', (e) => {
  console.log('Child clicked');
  // e.stopPropagation(); // 阻止继续向上传播
});

document.getElementById('parent').addEventListener('click', () => {
  console.log('Parent clicked');
});

document.addEventListener('click', () => {
  console.log('Document clicked');
});

2. Express中间件

Express框架的中间件机制也是责任链模式的实现。每个中间件可以决定是否处理请求或传递给下一个中间件。

const express = require('express');
const app = express();

// 中间件1
app.use((req, res, next) => {
  console.log('Middleware 1');
  next(); // 传递给下一个中间件
});

// 中间件2
app.use((req, res, next) => {
  console.log('Middleware 2');
  next();
});

// 路由处理
app.get('/', (req, res) => {
  res.send('Hello World');
});

app.listen(3000);

高级责任链模式实现

异步责任链

在实际开发中,处理过程可能是异步的。我们可以通过返回Promise来实现异步责任链。

class AsyncHandler {
  constructor() {
    this.next = null;
  }

  setNext(handler) {
    this.next = handler;
    return handler;
  }

  async handle(request) {
    if (this.next) {
      return await this.next.handle(request);
    }
    return null;
  }
}

class AuthHandler extends AsyncHandler {
  async handle(request) {
    console.log('AuthHandler processing');
    if (!request.user) {
      throw new Error('Unauthorized');
    }
    return await super.handle(request);
  }
}

class LoggingHandler extends AsyncHandler {
  async handle(request) {
    console.log('LoggingHandler processing');
    console.log(`Request from ${request.user}`);
    return await super.handle(request);
  }
}

class BusinessHandler extends AsyncHandler {
  async handle(request) {
    console.log('BusinessHandler processing');
    return { status: 'success', data: 'Some business data' };
  }
}

// 使用示例
(async () => {
  const auth = new AuthHandler();
  const logger = new LoggingHandler();
  const business = new BusinessHandler();

  auth.setNext(logger).setNext(business);

  try {
    const result = await auth.handle({ user: 'Alice' });
    console.log(result);
  } catch (error) {
    console.error(error.message);
  }
})();

动态责任链

有时候我们需要根据条件动态构建责任链。可以通过工厂方法或策略模式来实现。

class HandlerFactory {
  static createHandlers(config) {
    let firstHandler = null;
    let prevHandler = null;

    config.forEach(handlerConfig => {
      const handler = new handlerConfig.type();
      if (handlerConfig.condition) {
        handler.condition = handlerConfig.condition;
      }

      if (!firstHandler) {
        firstHandler = handler;
      }

      if (prevHandler) {
        prevHandler.setNext(handler);
      }

      prevHandler = handler;
    });

    return firstHandler;
  }
}

class ConditionalHandler extends Handler {
  handle(request) {
    if (this.condition && !this.condition(request)) {
      return super.handle(request);
    }
    console.log(`${this.constructor.name}处理请求`);
    return super.handle(request);
  }
}

class HandlerA extends ConditionalHandler {}
class HandlerB extends ConditionalHandler {}
class HandlerC extends ConditionalHandler {}

// 动态创建责任链
const chain = HandlerFactory.createHandlers([
  { type: HandlerA, condition: req => req.type === 'A' },
  { type: HandlerB, condition: req => req.value > 10 },
  { type: HandlerC }
]);

chain.handle({ type: 'A', value: 5 }); // 只有HandlerA处理
chain.handle({ type: 'B', value: 15 }); // HandlerB和HandlerC处理

责任链模式的变体

拦截过滤器模式

这是责任链模式的变体,允许在传递请求的过程中对请求或响应进行预处理和后处理。

class Filter {
  constructor() {
    this.next = null;
  }

  setNext(filter) {
    this.next = filter;
    return filter;
  }

  execute(request) {
    this.preProcess(request);
    if (this.next) {
      this.next.execute(request);
    }
    this.postProcess(request);
  }

  preProcess(request) {}
  postProcess(request) {}
}

class AuthFilter extends Filter {
  preProcess(request) {
    console.log('AuthFilter pre-processing');
    if (!request.token) {
      throw new Error('Authentication failed');
    }
  }

  postProcess(request) {
    console.log('AuthFilter post-processing');
  }
}

class LogFilter extends Filter {
  preProcess(request) {
    console.log('LogFilter pre-processing', request);
  }

  postProcess(request) {
    console.log('LogFilter post-processing', request);
  }
}

// 使用示例
const authFilter = new AuthFilter();
const logFilter = new LogFilter();

authFilter.setNext(logFilter);

try {
  authFilter.execute({ token: 'abc123', data: 'test' });
} catch (error) {
  console.error(error.message);
}

管道-过滤器模式

这种变体将处理过程分解为一系列独立的过滤器,通过管道连接,每个过滤器处理完数据后传递给下一个过滤器。

class Pipeline {
  constructor() {
    this.filters = [];
  }

  add(filter) {
    this.filters.push(filter);
    return this;
  }

  execute(input) {
    return this.filters.reduce((result, filter) => {
      return filter.process(result);
    }, input);
  }
}

class TrimFilter {
  process(input) {
    return input.trim();
  }
}

class ToUpperCaseFilter {
  process(input) {
    return input.toUpperCase();
  }
}

class ReplaceFilter {
  constructor(search, replacement) {
    this.search = search;
    this.replacement = replacement;
  }

  process(input) {
    return input.replace(this.search, this.replacement);
  }
}

// 使用示例
const pipeline = new Pipeline()
  .add(new TrimFilter())
  .add(new ToUpperCaseFilter())
  .add(new ReplaceFilter(/WORLD/g, 'JavaScript'));

const result = pipeline.execute('  hello world  ');
console.log(result); // "HELLO JAVASCRIPT"

责任链模式的优缺点

优点

  1. 降低耦合度:请求发送者不需要知道哪个对象会处理它的请求。
  2. 动态组合:可以动态地添加或修改处理链。
  3. 单一职责原则:每个处理者只需关注自己负责的部分。
  4. 灵活性:可以灵活地调整处理顺序或添加新的处理者。

缺点

  1. 请求可能未被处理:如果链中没有合适的处理者,请求可能得不到处理。
  2. 性能考虑:长链可能导致性能下降,特别是在异步场景中。
  3. 调试困难:请求的传递路径可能不太直观,增加调试难度。

与其他模式的关系

  1. 与命令模式:责任链模式通常与命令模式一起使用,其中命令对象作为请求在链中传递。
  2. 与组合模式:责任链模式的处理者可以使用组合模式来构建树状结构。
  3. 与装饰器模式:两者都基于递归组合,但装饰器模式增强对象功能,而责任链模式处理请求。

实际项目中的最佳实践

  1. 明确终止条件:确保链的末端有明确的处理方式,避免请求丢失。
  2. 控制链的长度:过长的链会影响性能,必要时可以考虑其他模式。
  3. 日志记录:在复杂的链中添加日志记录,方便调试。
  4. 错误处理:实现统一的错误处理机制,避免错误在链中丢失。
// 带有错误处理和日志记录的高级责任链实现
class AdvancedHandler {
  constructor(name) {
    this.name = name;
    this.next = null;
  }

  setNext(handler) {
    this.next = handler;
    return handler;
  }

  async handle(request) {
    try {
      console.log(`[${this.name}] 开始处理请求`);
      const result = await this.process(request);
      console.log(`[${this.name}] 处理完成`);
      return result;
    } catch (error) {
      console.error(`[${this.name}] 处理出错:`, error.message);
      if (this.next) {
        console.log(`[${this.name}] 将错误传递给下一个处理器`);
        return this.next.handle(request);
      }
      throw error;
    }
  }

  async process(request) {
    // 由子类实现具体处理逻辑
    if (this.next) {
      return this.next.handle(request);
    }
    throw new Error('没有处理器能够处理该请求');
  }
}

class DatabaseHandler extends AdvancedHandler {
  constructor() {
    super('DatabaseHandler');
    this.isConnected = false;
  }

  async connect() {
    // 模拟数据库连接
    await new Promise(resolve => setTimeout(resolve, 100));
    this.isConnected = true;
  }

  async process(request) {
    if (!this.isConnected) {
      await this.connect();
    }

    if (request.type === 'db_query') {
      // 模拟数据库查询
      await new Promise(resolve => setTimeout(resolve, 50));
      return { data: 'Database result' };
    }

    return super.process(request);
  }
}

class APICacheHandler extends AdvancedHandler {
  constructor() {
    super('APICacheHandler');
    this.cache = new Map();
  }

  async process(request) {
    if (request.type === 'api_request' && this.cache.has(request.url)) {
      return this.cache.get(request.url);
    }

    const result = await super.process(request);
    
    if (request.type === 'api_request') {
      this.cache.set(request.url, result);
    }

    return result;
  }
}

class APIHandler extends AdvancedHandler {
  constructor() {
    super('APIHandler');
  }

  async process(request) {
    if (request.type === 'api_request') {
      // 模拟API调用
      await new Promise(resolve => setTimeout(resolve, 200));
      return { data: 'API response' };
    }

    return super.process(request);
  }
}

// 使用示例
(async () => {
  const cacheHandler = new APICacheHandler();
  const apiHandler = new APIHandler();
  const dbHandler = new DatabaseHandler();

  cacheHandler.setNext(apiHandler).setNext(dbHandler);

  try {
    // API请求 - 第一次会调用API,第二次从缓存获取
    const apiRequest = { type: 'api_request', url: '/users' };
    console.log(await cacheHandler.handle(apiRequest));
    console.log(await cacheHandler.handle(apiRequest));

    // 数据库查询
    console.log(await cacheHandler.handle({ type: 'db_query' }));

    // 未知请求类型
    await cacheHandler.handle({ type: 'unknown' });
  } catch (error) {
    console.error('最终错误:', error.message);
  }
})();

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步