前言
从第一篇工厂模式开始,我会持续地更新每一种设计模式的内容,争取用通俗易懂的语言讲解和解释清楚。如果对你学习设计模式有帮助,请不要吝啬手中的赞~ 如果对文章内容有任何疑惑都可以在评论区提出和讨论~
本系列文章中的完整源码已上传 github 仓库,你可以在这里 github.com/FatMii/Desi...获取。
同样的,如果对你有帮助,请给我一个star~谢谢
设计模式合集链接:
Hello~大家,在前面的文章中已经学习了工厂模式
,单例模式
。本篇文章我们继续学习第三篇:责任链模式
介绍
责任链模式是一个设计模式的术语,但我会尽量用简单直观的方式来解释它。
首先我们可以拆解成两块内容:责任
与链
-
"责任"的概念
: 想象每个人(或每个模块、方法)都有自己的职责范围。当一个问题或任务来到他们面前时,如果这是他们应对的,他们就会处理这个任务。 -
"链"的概念
。单独一个人处理事情可能效率不够或能力有限,所以我们需要多个人一起协作。就像现实生活中的链条,只有多个环节才能一起形成一条完整的链。
结合起来,责任链模式
的含义就是:一个事件或请求在多个对象之间传递,每个对象都有机会处理这个请求。这个过程会一直持续,直到有一个对象能够处理它为止。这样不仅可以分散压力,还能确保更高效地处理问题。
在责任链模式中,每个处理对象都包含对下一个处理对象的引用
。当一个对象接收到请求后,它会根据条件决定是自己处理这个请求
,还是将其传递给链中的下一个对象
。这样,请求在链中传递,直到被处理或者整个链都无法处理该请求。
这种模式常用于处理不同种类的请求或在不同条件下需要不同处理的场景,例如不同级别的日志记录器
、不同类型的事件处理
等。责任链模式可以有效地减少对象间的耦合
,并提高系统的灵活性和可扩展性
代码实现
话不多说,我们用一个错误类型处理的例子来实现
步骤1:创建处理对象
javascript
function error400(err) {
if (err.code !== 400) {
return "nextSuccessor";
}
console.log("Handling 400 error");
}
function error500(err) {
if (err.code !== 500) {
return "nextSuccessor";
}
console.log("Handling 500 error");
}
function error600(err) {
if (err.code !== 600) {
return "nextSuccessor";
}
console.log("Handling 600 error");
}
我们设计了三种错误处理方法,分别应对状态码为400
、500
和600
的情况。在error400
方法中,我们会接收一个对象,并检查其状态码是否为400
。如果不是,方法将返回一个标识字符串"nextSuccessor"
以指示处理流程应继续。error500
和error600
方法的工作机制相同,这里不再详细说明。
步骤2:定义Chain类和实现链式处理逻辑
javascript
class Chain {
constructor(fn) {
this.fn = fn;
this.nextHandler = null;
}
setNextHandler(handler) {
this.nextHandler = handler;
}
passRequest(...args) {
const result = this.fn(...args);
if (result === "nextSuccessor") {
if (this.nextHandler) {
return this.nextHandler.passRequest(...args);
}
}
return result;
}
}
-
构造器(Constructor) :
constructor(fn)
:这个构造函数接收一个函数fn
作为参数。这个函数是当前链节点要处理的具体逻辑。this.fn = fn
:将传入的函数存储为类的一个属性,用于后续调用。this.nextHandler = null
:初始化一个nextHandler
属性,并设为null
。这个属性用来存储链中的下一个处理者。
-
设置下一个处理者(setNextHandler) :
setNextHandler(handler)
:这个方法接收一个handler
参数,这个参数是链中的下一个处理节点。this.nextHandler = handler
:将传入的处理者设置为当前处理节点的下一个处理者。
-
传递请求(passRequest) :
-
passRequest(...args)
:这个方法用来接收和处理请求。它接受任意数量的参数args
,这些参数是请求的数据。 -
const result = this.fn(...args)
:调用存储的函数fn
并传入参数,执行当前节点的处理逻辑,并将结果存储在result
中。 -
判断执行结果是不是
"nextSuccessor"
,如果是,代表当前节点无法处理,需要传递给链中的下一个处理者 -
if (this.nextHandler)
:如果存在下一个处理者(nextHandler
不是null
) 调用下一个处理者的passRequest
方法,并将当前的请求参数传递给它。 -
return result
:如果当前节点处理了请求(即fn
的结果不是"nextSuccessor"
),或者没有下一个处理者可以处理请求,则返回当前节点的处理结果。
-
步骤3: 使用
javascript
const c1 = new Chain(error400);
const c2 = new Chain(error500);
const c3 = new Chain(error600);
c1.setNextHandler(c2);
c2.setNextHandler(c3);
// Trigger error handling
c1.passRequest({ code: 500 }); // Only 500 error handler should activate
优点
优点
-
降低耦合度:
- 责任链模式让多个对象都有机会处理请求,从而将请求的发送者和接收者解耦。这样,各个处理者只需关注自己的责任范围,无需了解链中其他处理者的细节。
-
增强可扩展性:
- 可以动态地添加或修改处理链。如果需要新增一个处理步骤,只需增加一个新的链节点并适当配置其在链中的位置,而无需修改现有代码。
-
灵活分配责任:
- 可以根据需要在运行时重新组织链或改变成员的责任,使得系统更灵活应对变化。
-
分散请求的处理:
- 责任链模式可以将一个复杂的请求处理过程分散到多个处理者中,使得系统易于管理和维护。
缺点
-
性能问题:
- 每个请求都从链的开始处经过,直到有对象处理它为止。这可能会引入一定的处理延迟,尤其是在链较长的情况下。
-
责任划分不清:
- 如果链中的处理者没有妥善设计,可能会出现某个请求没有被任何处理者处理的情况,或者不明确哪个处理者应当负责处理特定请求。
-
复杂性增加:
- 使用责任链模式可能会使系统结构变得复杂,特别是链中的节点数目较多或者链的结构动态变化时。