JS设计模式 - 责任链模式在前端业务中的应用

重要的事情说三遍
https://mp.weixin.qq.com/s/75owDiZ1f20OW5EfEL6wAA
https://mp.weixin.qq.com/s/75owDiZ1f20OW5EfEL6wAA
https://mp.weixin.qq.com/s/75owDiZ1f20OW5EfEL6wAA
好了开始~

image

这个算是我第二次写责任链模式的内容了,上次是给团队做分享的时候,讨论了不少,回去之后我也重新思考了当初没想到的这些问题,重新修改该篇。希望能从此收获更多。

既然针对业务背景,那首先让我们去了解需求吧。相信这个需求场景经常能遇到。

场景描述

登录系统,需要检测是否配置1,配置2,配置…,配置n是否都配置完成了。如果未完成,则需要弹窗,让用户输入配置,配置过程较长,所以可以中途退出配置,直到下次登录或者配置的入口按钮,继续该次的配置。

image

直观的流程,只需要判断都是哪些个case,弹出对应的弹窗即可。很典型的if else if模型,那针对这无穷无尽的if else,可能我们还可以用switch case去处理,但总归不是这么明确。

如果这时候n和n+1之间需要增加配置n.1,我们需要打开判断的函数,增加一个case,然后把n的弹窗,在完成的时候指向n.1,n.1的完成指向n+1。

如果有帮忙把流程节点很清楚的以代码表现出来,就不再需要关注其他弹窗,直接对n和n+1操作;仅仅把代码按照某种顺序组合起来,需求反馈不清晰的时候,你可能得从第一个函数一直找到所需要的函数为止。


铺垫了这么多,其实是想引入一些比较装逼的设计模式。好在以后面试时候能吹上一波。那我们用什么模式好呢?

翻了一番以前大学时候学过的设计模式书本,我们还是来搜索看看什么是责任链模式吧。

菜鸟教程~

image

责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式

它的主要意图,主要解决:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止

职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。

通过上面凑字数的图片和菜鸟教程复制过来文字。我们大概知道了它是啥了,接下来再抽象一下,把它画成图。

image

从实现上简单的说,就是每一个具体的处理者,在handleRequest处理请求完毕之后,决定是否要传给下一处理者去处理,过程中处理者只需要关注的是是否处理,不处理就往下传递。

但是实际上,我们应该关注链的组成顺序,因为链的客户只需要有节点处理这个数据的请求,而链的实现者肯定是希望有个接收处理者的优先级,链不应该只有一个能处理的节点。(比如说李四是个前端总监,你说他会希望一个改按钮颜色的需求传到到李四,或者只有他能解决么)

所以这抽象的链条代表了一个处理逻辑,把这部分也抽象成为一个类,我们得到了俩:

image

材料都准备好了,在前端,JS上我们该如何实现呢?

我用vscode,你呢?哈哈哈哈

chainNode

class ChainNode {
    constructor(main, next, options) {
        this.main = main
        this.next = next
        this.options = options
    }
    start () {
        let res = this.main(...arguments)
        res && this.next.start(...arguments)
    }
    setNext (callback) {
        this.next = callback
    }
}

ResponsibilityChain

class ResponsibilityChain {
    constructor() {
        this.chainNodes = {} // 责任节点
    }
    getChainNodes(chainName) { // 获取责任节点
        return this.chainNodes[chainName]
    }
    setChainNodes(name, chainNode) { // 设置责任节点
        this.chainNodes[name] = chainNode
    }
    insertChainNode () {}
    chainConstitute(array) { // 链
        for (let index = 0; index < array.length; index++) {
            let element = this.chainNodes[array[index]]
            let next = this.chainNodes[array[index + 1]]
            element.next = next
        }
    }
}

测试一下

function template_fn1 (tmp) {
    console.log('配置1', tmp)
    if ('have配置1') {
        return true
    }
    //
    alert('输入配置1')
    return false
}
function template_fn2 (tmp) {
    console.log('配置2', tmp)
    return true
}
function template_fn3 (tmp) {
    console.log('配置3', tmp)
    return false
}
function template_fn4 (tmp) {
    console.log('配置4', tmp)
    return false
}
​
let responsibilityChain = new ResponsibilityChain()
responsibilityChain.setChainNodes('chainNode_1', new ChainNode(template_fn1))
responsibilityChain.setChainNodes('chainNode_2', new ChainNode(template_fn2))
responsibilityChain.setChainNodes('chainNode_3', new ChainNode(template_fn3))
responsibilityChain.setChainNodes('chainNode_4', new ChainNode(template_fn4))
responsibilityChain.chainConstitute(['chainNode_1', 'chainNode_2', 'chainNode_3', 'chainNode_4'])
let firstNode = responsibilityChain.getChainNodes('chainNode_1')
firstNode.start('handleRequest')
​
// 配置1 handleRequest
// 配置2 handleRequest
// 配置3 handleRequest

到这里,我们终于可以正式的对这个业务逻辑写一些代码了!太难了

针对每一设置的case,我们都去判断它是否有配置的数据,如果有则返回true,将当期账号的配置数据往下传递;如果没有,则返回false,并且弹窗要求输入配置信息1;

function template_fn1 (tmp) {
    console.log('配置1', tmp)
    if ('have配置1') {
        return true
    }
    //
    alert('输入配置1')
    return false
} 

一直到链的结束,都没有弹窗的话证明所有的配置信息都已经存在。

关于【配置信息1】输入完毕之后呢。输入完毕,我们应该已经把该数据更新到当前的账户上了。那么,这个更新之后的数据,就是一个新的处理对象,再把它交给这个链来处理。

打个比方,改按钮颜色的需求由张三实习生修改完毕上线,项目的状态(数据)更新,再把项目往责任链输入,就该到李四总监去给客户交付项目了。

再回来需要增加n.1的问题,我们在修改的时候,在构建链的时候,一眼就能看到n和n+1在哪儿,只需要往他们之间添加n.1,更新的处理对象还是往链输入即可。(这个修改的地方还可以有链表结构优化)

这样我们就做到了对修改关闭,对扩展开放的原则。每一个node都是隔离的单一原则。

至此,这就是我所理解的责任链模式的应用。不对之处欢迎指出。受气了,才有动力验证代码,不然学不动啦,手动狗头🐶。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容