什么是职责链模式
当一个对象A要办个事儿,就向一个处理对象B发起请求,如果B不处理,可以把请求转给C,如果C不处理,又可以把请求转给D。一直到有一个对象愿意处理这个请求为止。
B -> C -> D 这就是一条
职责链
。如果请求一直没人处理,那么这事儿就黄了,搞不定。
A在一开始是不知道自己会被谁处理的。
实例:俺是个鉴黄的!
下面举具体的例子来说明。
俺在路上看到一则新闻说关于「鉴黄师」的,心向往之,不禁开了个脑洞。。
现在,假设你是一名拥有强大技能的「鉴黄师」。
当然,因为你是鉴黄师,不是一个只是爱看黄的普通宅男,那么你肯定是要比一般人牛逼的。
那牛逼在哪呢,就在于,你有一套极其牛逼的自动化工具链
。
恩,提到这个闪瞎狗眼的神器,必须得先说下工作内容,额,就是鉴黄嘛。比如,把一个文件夹拖进去,自动鉴定里面的内容是不是黄色内容。如果是黄色内容就嗷嗷叫报警。你们还真一个个点开看啊,营养你跟得上啊,敢不敢更low一点。
那么这工具是怎么工作的呢?
- 首先先拿到文件夹下所有文件。废话吗这不。
- 然后工具中的「番号模块」开始工作,具有黄色特征的文件名,比如
ebody
,snis
,SOE
之类,如果碰上,就是黄的,恩那么就嗷嗷报警。- 没碰上怎么办呢,「番号模块」就表示无能为力了,把它交给一个很强大的模块「md5模块」。这个
md5
是啥玩意儿呢,就是一个文件有唯一的标识符,把这标识符和国内最大的影片存储中心百度云
数据库中的标识符做对比。说白了很简单,这部影片标识符如果和百度云禁片的标识符一样,那么肯定是黄的嘛。牛逼吧。- 最后一种情况,某片连百度云上都没有,那肿么办,「md5模块」只好把这个文件夹交给最终的大招「视频图像识别模块」,自动识别视频中的图像,如果符合xx特征的,那么就是黄的。
恩,所以这个工具就是这么工作的:
番号模块 -> md5模块 -> 视频图像识别模块
这就形成了一条职责链
,各个模块各司其职,逐级传递。
Javascript实现
那么我们怎样用js把它抽象出来呢?
- 首先,这仨东西都是模块,我们应该能想到建立一个「模块类」。
- 每个模块都有处理功能,那么模块类应该有一个抽象的方法
handle
。 - 每个模块都可以设置「下级模块」,如果自己处理不了,就给下级模块处理(当然,在例子中,视频图像识别模块是没有下级的,它处理不了的,整个工具就都处理不了了)。
那么,先建立一个模块类
:
接着来实现番号模块、md5模块、视频图像处理模块。逻辑基本都是一样的:
关于extend原型继承函数可以看我的这篇文章。
现在已经基本实现好了。那么做一个具体的调用,这里我们假设取得了要鉴黄的文件,参数files
是个数组:
由上例可见,我们只要将files
传给职责链中的第一环myIdentifierHandler
就可以了,如果它处理不了,就会将请求传给下一环节。
同时我们可以看出一个重点问题:
我们可以自由设定一个handler的下级。
比如我们现在的职责链是:
番号模块 -> md5模块 -> 视频图像识别模块
来了一个新任务,你一瞅,我去,今天是1月2号,来了个1月1日 新作34连发
,这么新的片子,百度云上肯定没有啊,那md5模块检测就基本没有用了,而且这个模块检测还非常耗时,那么你完全可以跳过md5模块:
这样,可以根据实际的情况,自由地选择下级职责链中的下一环,在特定的场景中就可以节约性能开销
。
多扯两句:事件委托 / 原型链
学过BOM知识的童鞋肯定都有了解,浏览器的「事件冒泡」、「事件委托」or「事件代理」的过程,实际也可以用职责链
来解释:一个事件在某个节点上被触发,然后向根节点传递, 直到被节点捕获。
Javascript的原型链
查找方法也有职责链
的影子:在子类上调用一个方法,如果自身找不到,就沿着原型链一级级向上查找。
总结
职责链模式可以让对象得到灵活、高效的处理,减轻请求对象和处理对象的耦合。
是否明白呢亲?
以上。