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都是隔离的单一原则。

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

你可能感兴趣的:(JS设计模式 - 责任链模式在前端业务中的应用)