您现在的位置是:网站首页 > 责任链模式(Chain of Responsibility)的请求处理流程文章详情
责任链模式(Chain of Responsibility)的请求处理流程
陈川
【
JavaScript
】
35071人已围观
10370字
责任链模式的基本概念
责任链模式是一种行为设计模式,允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下一个处理者。这种模式解耦了请求的发送者和接收者,使得多个对象都有机会处理请求。
在JavaScript中,责任链模式通常表现为一个对象包含对另一个对象的引用,形成一条链。当请求到达某个对象时,这个对象要么处理它,要么将其传递给链中的下一个对象。
责任链模式的结构
典型的责任链模式包含以下几个关键组成部分:
- Handler(处理者):定义处理请求的接口,通常包含一个方法来设置下一个处理者,以及一个方法来处理请求。
- ConcreteHandler(具体处理者):实现处理请求的具体逻辑,决定是否处理请求以及是否将请求传递给下一个处理者。
- 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
责任链模式的应用场景
责任链模式特别适用于以下场景:
- 多级审批流程:如请假审批,不同级别的领导有不同的审批权限。
- 事件冒泡机制:DOM事件处理就是典型的责任链模式实现。
- 中间件管道:Express/Koa等框架的中间件机制。
- 错误处理:尝试多个错误处理器直到找到合适的处理方式。
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"
责任链模式的优缺点
优点
- 降低耦合度:请求发送者不需要知道哪个对象会处理它的请求。
- 动态组合:可以动态地添加或修改处理链。
- 单一职责原则:每个处理者只需关注自己负责的部分。
- 灵活性:可以灵活地调整处理顺序或添加新的处理者。
缺点
- 请求可能未被处理:如果链中没有合适的处理者,请求可能得不到处理。
- 性能考虑:长链可能导致性能下降,特别是在异步场景中。
- 调试困难:请求的传递路径可能不太直观,增加调试难度。
与其他模式的关系
- 与命令模式:责任链模式通常与命令模式一起使用,其中命令对象作为请求在链中传递。
- 与组合模式:责任链模式的处理者可以使用组合模式来构建树状结构。
- 与装饰器模式:两者都基于递归组合,但装饰器模式增强对象功能,而责任链模式处理请求。
实际项目中的最佳实践
- 明确终止条件:确保链的末端有明确的处理方式,避免请求丢失。
- 控制链的长度:过长的链会影响性能,必要时可以考虑其他模式。
- 日志记录:在复杂的链中添加日志记录,方便调试。
- 错误处理:实现统一的错误处理机制,避免错误在链中丢失。
// 带有错误处理和日志记录的高级责任链实现
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);
}
})();