JS设计模式——发布/订阅模式

发布/订阅模式和观察者模式的区别

有人说发布/订阅模式就是观察者模式,有人说发布/订阅模式是观察者的变种。不管怎样,必须承认他们之间是有区别的。

其中最主要的区别就是在发布/订阅模式中多了一层主题/事件通道。

回想在观察者模式中,主题和观察者是直接发生关系的,观察者需要注册到主题中去。而在发布/订阅模式中,发布者和订阅者并不知道彼此的存在,他们都直接和中间层(主题/事件通道)发生关系。
在这里插入图片描述
我们还是拿餐馆吃饭来举例。

在观察者模式中,我们把餐馆(目标)看成一个整体,和客户(观察者)直接发生关系。

在发布/订阅模式中,我们把餐馆分成两部分,后厨(发布者)和前台(主题/事件通道)。而前来吃饭的顾客就是订阅者。

现在有顾客进来吃饭,会先去前台点餐。也就是订阅过程。顾客也不会直接跑到后厨去点餐。

后厨做好的餐,会通知前台。这也就是发布过程。

前台会把做好的餐,端给对应的顾客。这就是触发过程。
实现

下面我们来实现一个简单的发布/订阅模式:

var pubsub = {}

;(function(q) {
    var topics = {}
    var subUid = -1

// 发布或广播事件,包含特定的 topic 和参数。
q.publish = function(topic, args) {
    if (!topics[topic]) {
        return false
    }
    var subscribes = topics[topic]
    var len = subscribes ? subscribes.length : 0

    while (len--) {
        subscribes[len].func(topic, args)
    }

    return this
}

// 订阅事件,通过特定的 topic 和 回调函数。在 topic/evnet 触发时会执行回调。
q.subscribe = function(topic, func) {
    if (!topics[topic]) {
        topics[topic] = []
    }

    var token = (++subUid).toString()

    topics[topic].push({
        token: token,
        func: func
    })

    return token
}

// 取消订阅。通过订阅时生成的引用标记。
q.unsubscribe = function(token) {
    for (var m in topics) {
        if (topics[m]) {
            for (var i = 0, j = topics[m].length; i < j; i++) {
                if (topics[m][i].token === token) {
                    topics[m].splice(i, 1)
                    return token
                }
                
            }
        }
    }
}

return this
}
)(pubsub)

使用

用代码的方式来模仿下餐馆点餐的过程。

// A 顾客来餐馆点了一份牛肉拉面,不要辣。(订阅过程)
var food1 = pubsub.subscribe('beef ramen', function(topic, args) {
    if (args === 'not spicy') {
        console.log(topic + ' ' + args)
    }
})

// B 顾客来餐馆也点了一份牛肉拉面,正常做。(订阅过程)
var food2 = pubsub.subscribe('beef ramen', function(topic, args) {
    if (args === 'normal') {
    	console.log(topic + ' ' + args)
    }
})

// 后厨做好一份牛肉拉面,通知前台。
// 前台通知所有点牛肉拉面的顾客,并告诉顾客这碗面没放辣椒。
// 顾客根据自己的需求去拿餐。(发布触发过程)
// 打印 'beef ramen not spicy'
pubsub.publish('beef ramen', 'not spicy')

// A 顾客按自己需求拿到饭,开始吃饭。(取消订阅)
pubsub.unsubscribe(food1)

// 后厨做好一份牛肉拉面,通知前台。
// 前台通知所有点牛肉拉面的顾客,并告诉顾客这碗面正常做。
// 顾客根据自己的需求去拿餐。(发布触发过程)
// // 打印 'beef ramen normal'
pubsub.publish('beef ramen', 'normal')

// B 顾客按自己需求拿到饭,开始吃饭。(取消订阅)
pubsub.unsubscribe(food2)

// 由于 A、B 顾客都已经吃到了拉面,并取消了订阅。
// 已经没有吃拉面的顾客了。
// 这个时候,前台再通知拉面做好了,就没有人消费了。
pubsub.publish('beef ramen', 'normal')

参考

《JavaScript 设计模式》 —— Addy Osmani

作者:userkang
来源:CSDN
原文:https://blog.csdn.net/userkang/article/details/87192128
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值