Chain of Responsibility(职责链模式)属于行为型模式。行为型模式不只描述对象或类的模式,还描述它们之间的通讯模式,好比对操做的处理应该如何传递等等。前端
意图:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。git
几乎全部设计模式,在了解到它以前,笔者就已经在实战中遇到过了,所以设计模式的确是从实践中得出的真知。但另外一方面,若是没有实战的理解,单看设计模式是枯燥的,并且难以理解的,所以你们学习设计模式时,要结合实际问题思考。
若是看不懂上面的意图介绍,没有关系,设计模式须要在平常工做里用起来,结合例子能够加深你的理解,下面我准备了三个例子,让你体会什么场景下会用到这种设计模式。github
设想咱们要为一个后端框架实现中间件(知道 Koa 的同窗能够理解为 Koa 的洋葱模型),在代码中能够插入任意多个中间件,每一个中间件均可以对请求与响应进行处理。typescript
因为每一个中间件只响应本身感兴趣的请求,所以只有运行时才知道这个中间件是否会处理请求,那么中间件机制应该如何设计,才能保证其功能和灵活性呢?后端
若是一个大型系统中,任何一个模块点击都会弹出帮助文案,但并非每一个模块都有帮助文案的,若是一个模块没有帮助文案,则显示其父级的帮助文案,若是再没有,就继续冒泡到整个应用,展现应用级别的兜底帮助文案。这种系统应该如何设计?设计模式
其实 JS 事件冒泡机制就是个典型的职责链模式,由于任何 DOM 元素均可以监听好比 onClick
,不只能够本身响应事件,还可使用 event.stopPropagation()
阻止继续冒泡。浏览器
JS 事件冒泡机制对前端来讲太常见了,但咱们换个角度,站在点击事件的角度理解,就能从新发现其设计的精妙之处:微信
点击事件是叠加在每层 dom 上的,因为 dom 对事件的处理和绑定是动态的,浏览器自己不知道哪些地方会处理点击事件,但又要让每层 dom 拥有对点击事件的 “平等处理权”,因此就产生了冒泡机制,与事件阻止冒泡功能。框架
通用帮助文案和 JS 事件冒泡很相似,只是把点击事件换成了弹出帮助文案罢了,其场景机理是同样的。dom
说到这,咱们能够再从新理解一下职责链模式的意图:
意图:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
请求指的是某个触发机制产生的请求,是一个通用概念。“避免请求的发送者和接收者之间的耦合关系”,指的是若是咱们只有一个对象有处理请求的机会,那接收者就与发送者之间耦合了,其余接收者必须经过这个接收者才能继续处理,这种模式不够灵活。
后半句描述的是如何设计,能够实现这个灵活的模式,即将对象连成一条链,沿着链条传递该请求,直到有一个对象处理它为止。还要理解到,任何一个对象都拥有阻断请求继续传递的能力。
在中间件机制的例子中,后端 Web 框架对 Http 请求的处理就是个运用职责链模式的典型案例,由于后端框架要处理的请求是平行关系,任何请求均可能要求被响应,但对请求的处理是经过插件机制拓展的,且对每一个请求的处理都是一个链条,存在处理、加工、再处理的逻辑关系。
Handler 就是对请求的处理,能够看到这里是一条环路,只要处理完以后就能够交给下一个 Handler 进行处理,能够在中途拦截后中断,也能够穿透整条链路。
ConcreteHandler
是具体 Handler 的实现,他们都须要继承 Handler 以具有相同的 HandleRequest
方法,这样每个处理中间件就都拥有了处理能力,使得这些对象连成的链条能够对请求进行传递。
职责链实现方式很是多,好比 Koa 的洋葱模型实现原理就值得再写一篇文章,感兴趣的同窗能够阅读 co 源码。这里仅介绍最简单场景的实现方案。
职责链的简单实现模式也分为两种,一种是每一个对象自己维护到下一个对象的引用,另外一种是由 Handler 维护后继者。
下面例子使用 typescript 编写。
`public class Handler {
private nextHandler: Handler
public handle() {
if(nextHandler) {
nextHandler.handle()
}
}
}
`
每一个 Handler 的默认行为就是触发下一个链条的 handle
,所以什么都不作的话,这个链条是彻底打通的,所以咱们能够在链条的任何一环进行处理。
处理的方式就是重写 handle
函数,咱们在重写时,能够维持对 nextHandler.handle()
的调用,以使得链条继续向后传递,也能够不调用,从而终止链条向后传递。
职责链模式不保证每一个中间件都有机会处理请求,由于中间件顺序的问题,后面中间件可能被前面的中间件阻断,所以当中间件之间存在不信任关系时,职责链模式并不能保证中间件调用的可靠性。
另外就是不要扩大设计模式的使用范围,对一堆对象的连续调用就不必使用职责链模式,由于职责链适合处理对象数量不肯定、是否处理请求由每一个对象灵活决定的场景,而肯定了对象数量以及是否调用的场景,就不必使用职责链模式了。
职责链模式是插件机制经常使用的设计模式,在事件机制、请求处理中有普遍的应用。
职责链模式还能够与组合模式组合使用,由于组合模式描述的是一种统一管理的树形结构,每一个节点均可以把本身的父节点做为后继节点。实际上 dom 结构就是一种组合模式,事件冒泡就是在其基础上拓展的职责链模式。
讨论地址是: 精读《设计模式 - Chain of Responsibility(职责链模式)》· Issue #292 · dt-fe/weekly
若是你想参与讨论,请 点击这里,每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。
关注 前端精读微信公众号
版权声明:自由转载-非商用-非衍生-保持署名( 创意共享 3.0 许可证)