美文网首页
JS设计模式 - 责任链模式在前端业务中的应用

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

作者: 斯文的烟鬼去shi吧 | 来源:发表于2020-04-07 18:29 被阅读0次

    重要的事情说三遍
    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都是隔离的单一原则。

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

    相关文章

      网友评论

          本文标题:JS设计模式 - 责任链模式在前端业务中的应用

          本文链接:https://www.haomeiwen.com/subject/pwtophtx.html