JS发布-订阅模式

作者: ThomasCho | 来源:发表于2018-06-09 14:26 被阅读1394次

    发布-订阅模式广泛应用于异步编程中,这是一种替代传递回调函数的方案。

    现实中的例子:

          小明想买房,到了售楼处被告知,该楼盘的房子早已售罄。售楼MM告诉小明,不久后还有一些尾盘推出,时间还未定。
          小明记下了售楼处的电话,以后每天都会打电话询问是否可购买。除了小明,还有小红、小强也会每天向售楼处咨询这个问题。可能售楼处每天回答 1000个相同内容的电话。
    当然现实中销售公司会一一将客户的电话记录下来,新楼盘推出的时候,售楼 MM会翻开花名册,遍历上面的电话号码,依次发送一条短信来通知他们。

    发布 - 订阅模式的作用

          购房者不用再天天给售楼处打电话咨询开售时间,在合适的时间点,售楼处作为发布者会通知这些消息订阅者
          购房者和售楼处之间不再强耦合在一起,当有新的购房者出现时,他只需把手机号码留在售楼处,售楼处不关心购房者的任何情况。 而售楼处的变动也不会影响购买者,比如售楼 MM 离职,这些改变都跟购房者无关,只要售楼处记得发短信这件事情

    发布订阅模式可以取代对象之间硬编码的通知机制,一个对象不用再显式地调用另一个对象的某个接口,让两个对象低耦合地联系在一起。
    其实只要我们曾经在DOM上绑定过事件,就已经用过此模式:

    document.body.addEventListener('click', () => {
        alert('hello world')
    })
    document.body.click()
    
    以下用发布-订阅模式,写以下购房者与售楼处的故事
    let event = {
        clientList: {},
        listen (key, fn) {
            if (!this.clientList[key]) {
                this.clientList[key] = []
            }
            this.clientList[key].push(fn)   // 订阅的消息添加进缓存列表
        },
        trigger (type, money) {
            let fns = this.clientList[type]
            if (!fns || fns.length === 0) { // 如果没有绑定对应的消息
                return false
            }
            fns.forEach(fn => {
                fn.apply(this, [money])
            })
        }
    }
    
    // 再定义一个installEvent函数,用于给所有对象动态安装发布-订阅功能
    // 如:另一家售楼处也想要这个功能,就可以调用这个注册了,不同再写多一次这段代码
    let installEvent = obj => {
        for (let i in event) {
            obj[i] = event[i]
        }
    }
    
    // 给售楼处对象salesOffices动态增加发布-订阅功能
    let salesOffices = {}
    installEvent(salesOffices)
    // 小明订阅信息
    salesOffices.listen('squareMeter88', price => {
        console.log('小明,你看中的88平方的房子,价格=' + price)
    })
    // 小光订阅信息
    salesOffices.listen('squareMeter88', price => {
        console.log('小光,你看中的88平方的房子,价格=' + price)
    })
    // 小红订阅信息
    salesOffices.listen('squareMeter100', price => {
        console.log('小红,你看中的100平方的房子,价格=' + price)
    })
    salesOffices.trigger('squareMeter88', 2000000)
    salesOffices.trigger('squareMeter100', 2500000)
    

    运行结果:

    小明,你看中的88平方的房子,价格=2000000
    小光,你看中的88平方的房子,价格=2000000
    小红,你看中的100平方的房子,价格=2500000
    

    总结

          发布 — 订阅模式的优点非常明显,一为时间上的解耦,二为对象之间的解耦。它的应用非常广泛,既可以用在异步编程中,也可以帮助我们完成更松耦合的代码编写。发布 — 订阅模式还可以用来帮助实现一些别的设计模式,比如中介者模式。 从架构上来看,无论是 MVC还是 MVVM,都少不了发布 — 订阅模式的参与,而且JavaScript本身也是一门基于事件驱动的语言。

    缺点

          当然,发布 — 订阅模式也不是完全没有缺点。创建订阅者本身要消耗一定的时间和内存,而且当你订阅一个消息后,也许此消息最后都未发生,但这个订阅者会始终存在于内存中。另外,发布 — 订阅模式虽然可以弱化对象之间的联系,但如果过度使用的话,对象和对象之间的必要联系也将被深埋在背后,会导致程序难以跟踪维护和理解。特别是有多个发布者和订阅者嵌套到一起的时候,要跟踪一个 bug不是件轻松的事情。

    相关文章

      网友评论

        本文标题:JS发布-订阅模式

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