观察者模式-发布订阅模式-及其实现


题意描述:

观察者模式和发布订阅模式有什么不同 ? 手写一个观察者模式的例子 ?


解题思路:
Alice: 上次讲了观察者模式,发布订阅模式是什么 ?
Bob: 和观察者模式很类似,发布订阅模式其实属于广义上的观察者模式。在观察者模式中,观察者需要直接订阅目标事件。在目标发出内容改变的事件后,直接接收事件并作出响应。而在发布订阅模式中,发布者和订阅者之间多了一个调度中心。调度中心一方面从发布者接收事件,另一方面向订阅者发布事件,订阅者需要在调度中心中订阅事件。通过调度中心实现了发布者和订阅者关系的解耦。使用发布订阅者模式更利于我们代码的可维护性。
Alice: 也就是说发布订阅模式就是在 观察者模式的 被观察者 和 观察者之间加了一层 调度中心 ?
Bob: 是的,下面的图解释的很清楚,就是多了一个调度中心。即实现了 发布者 和 订阅者 之间的解耦,还可以在 调度中心加一些细粒度的控制,就是代码可能会麻烦一点。
在这里插入图片描述
在这里插入图片描述
Alice: 写段代码来遛一遛 😏
Bob: 我来一个发布订阅模式吧。

// eventChannel 后是一个 IIEF 立即执行的函数表达式
        var eventChannel = (function () {
            var events = {};
            // 闭包,用于存储调度中心接收的消息
            return {
                // 订阅者通过 subscribe 函数订阅event事件
                subscribe: function (event, handler) {
                    if (!events.hasOwnProperty(event)) {
                        events[event] = [];
                    }
                    events[event].push(handler);
                },

                receiveEvent: function (event) {
                    if (events.hasOwnProperty(event)) {
                        console.log(`非首次接收  ${event}, 尝试 FireEvent`);
                        this.fireEvent(event, "from receiveEvent");
                    } else {
                        console.log(`首次接收  ${event}`);
                        events[event] = [];
                    }
                },

                // 调度中心选择 触发事件处理函数
                fireEvent: function (event, msg) {
                    if (events.hasOwnProperty(event)) {
                        // 有对应的事件处理函数
                        events[event].forEach(handler => {
                            handler(msg);
                            // 调用每个事件处理函数
                        });
                    }
                },

                remove: function (event, handler) {
                    // 移除事件的某一个处理函数
                    if (events.hasOwnProperty(event)) {
                        let index = events[event].indexOf(handler);
                        // 放心,indexOf 使用的是 ===
                        if (index !== -1) {
                            events[event].splice(index, 1);
                        }
                    }
                },

                removeAll: function (event) {
                    // 移除某个事件的所有处理函数
                    if (events.hasOwnProperty(event)) {
                        events[event] = [];
                    }
                }
            }
        })();

        var handler = function (msg) {
            console.log(`handler is running : ${msg}`);
        }

        // publisher 通过 receiveEvent 来发布事件
        eventChannel.receiveEvent('AREUOK');
        eventChannel.subscribe('AREUOK', handler);
        eventChannel.receiveEvent('AREUOK');
        eventChannel.fireEvent('AREUOK', 'Year, I AM OK');
        // 首次接收  AREUOK
        // 非首次接收  AREUOK, 尝试 FireEvent
        // handler is running: from receiveEvent
        // handler is running: Year, I AM OK

Alice: 你这里是没有写 发布者 publisher 吗,还有订阅者 subscriber 也没写 。
Bob: 不过我写了 调度中心和 二者 交互的函数呀, receiveEvent, subscribe, fireEvent 应该能够展示 发布订阅模式的工作机理了,发布者和订阅者只需要调用对应的函数就好了。
Alice: 不错不错,我来一个 观察者模式吧。

       var Observer = function(name){
            // 观察者的构造函数
            this.name = name;
            this.update = function(msg){
                console.log(`${this.name} get msg: ${msg}`);
            } 
        }

        var Subject = function(name){
            // 被观察者构造函数
            this.name = name;

            this.observers = [];

            this.addObserver = function(observer){
                this.observers.push(observer);
            }

            this.removeObserver = function(observer){
                let index = this.observers.indexOf(observer);
                if(index !== -1){
                    this.observers.splice(index, 1);
                }
            }

            this.notifyAll = function(){
                this.observers.forEach(observer => {
                    observer.update(this.name + " ~ msg by nofifyAll");
                });
            }
        }

        var ob1 = new Observer('Alice'),
            ob2 = new Observer('Bob');
        
        var sub = new Subject('winter is coming');
        sub.addObserver(ob1);
        sub.addObserver(ob2);
        sub.notifyAll();
        // Alice get msg: winter is coming ~msg by nofifyAll
        // Bob get msg: winter is coming ~msg by nofifyAll

代码:

  • 在上面

易错点:

  • 观察者模式 和 订阅发布模式 是有区别的。

总结:

  • 在观察者模式中,观察者是知道Subject的,Subject一直保持对观察者进行记录。然而,在发布订阅模式中,发布者和订阅者不知道对方的存在。它们只有通过调度中心进行通信。
  • 在发布订阅模式中,组件是松散耦合的,正好和观察者模式相反。
  • 观察者模式大多数时候是同步的,比如当事件触发,Subject就会去调用观察者的方法。而发布-订阅模式大多数时候是异步的(使用消息队列)

参考文献:


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值