美文网首页
观察者模式 与 发布订阅模式

观察者模式 与 发布订阅模式

作者: Cherry丶小丸子 | 来源:发表于2023-07-26 17:01 被阅读0次
    观察者模式(Observer)

    它是软件设计模式的一种。在此种模式中,一个目标对象管理着所有相依(依赖)于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统

    观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,简单来说,观察者模式就是,一个对象(被观察者)的状态发生改变时,会通知所有依赖它的对象(观察者),观察者模式有一个别名叫发布-订阅模式

    发布-订阅模式(Publisher-Subscriber)

    其实 23 种基本的设计模式中并没有发布-订阅模式,上面也说了,他只是观察者模式的一个别称。但是经过时间的沉淀,似乎他已经强大了起来,已经独立于观察者模式,成为另外一种不同的设计模式。在现在的发布订阅模式中,称为发布者的消息发送者不会将消息直接发送给订阅者,这意味着发布者和订阅者不知道彼此的存在。在发布者和订阅者之间存在第三个组件,称为消息代理或调度中心或中间件,它维持着发布者和订阅者之间的联系,过滤所有发布者传入的消息并相应地分发它们给订阅者

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

    观察者模式是,当被观察者的数据发生变化时,调用被观察者的 notify 方法,去通知所有观察者执行 update 方法进行更新
    对于发布-订阅模式,首先发布者与订阅者互相并不知道彼此的存在,他们是通过事件中心来进行调度的,发布者在事件中心发布一个对应的事件主题,订阅者在事件中心订阅一个事件主体,当订阅者去触发 emit 时就去执行发布者所发布的事件

    Vue 展示了其设计模式的案例体现,Vue 的双向数据绑定使用了观察者模式,其中央事件总线 EventBus 使用了发布-订阅模式

    详细请看:https://blog.51cto.com/u_15283585/2959669
    观察者模式和发布-订阅模式的区别:https://blog.csdn.net/qq_38128179/article/details/111307528

    手写观察者模式
    // 被观察者:Dep
    class Dep {
        constructor() {
            // 记录所有的观察者
            this.subs = []
        }
        // 添加观察者
        addSub(sub) {
            // 如果该观察者存在且有 update 方法,就将其添加到 subs 数组中
            if (sub && sub.update) {
                this.subs.push(sub)
            }
        }
        // 移除观察者
        removeSub(sub) {
            if (this.subs.length) {
                let index = this.subs.indexOf(sub)
                if (index > -1) {
                    this.subs.splice(index, 1)
                }
            }
        }
        // 发布更新通知
        notify() {
            this.subs.forEach(item => {
                item.update()
            })
        }
    }
    
    // 观察者:Watcher
    class Watcher {
        update() {
            console.log("****更新相关数据****")
        }
    }
    
    let dep = new Dep();
    let watcher1 = new Watcher();
    let watcher2 = new Watcher();
    
    // 添加新的观察者
    dep.addSub(watcher1)
    dep.addSub(watcher2)
    dep.removeSub(watcher2)
    // 发布
    dep.notify();
    
    手写发布-订阅模式
    class Observer {
        constructor() {
            this.message = {} // 消息队列
        }
    
        /**
         * `$on` 向消息队列添加内容 
         * @param {*} type 事件名 (事件类型)
         * @param {*} callback 回调函数
         */
        $on(type, callback) {
            // 判断有没有这个属性(事件类型)
            if (!this.message[type]) {
                // 如果没有这个属性,就初始化一个空的数组
                this.message[type] = [];
            }
            // 如果有这个属性,就往他的后面 push 一个新的 callback
            this.message[type].push(callback);
        }
    
        /**
         * $off 删除消息队列里的内容
         * @param {*} type 事件名 (事件类型)
         * @param {*} callback 回调函数
         */
        $off(type, callback) {
            // 判断是否有订阅,即消息队列里是否有 type 这个类型的事件,没有的话就直接 return
            if (!this.message[type]) return;
            // 判断是否有 callback 这个参数
            if (!callback) {
                // 如果没有 callback,就删掉整个事件
                this.message[type] = undefined;
                return;
            }
            // 如果有callback,就仅仅删掉 callback 这个消息(过滤掉这个消息方法)
            this.message[type] = this.message[type].filter((item) => item !== callback);
        }
    
        /**
         * $emit 触发消息队列里的内容
         * @param {*} type 事件名 (事件类型)
         */
        $emit(type) {
            // 判断是否有订阅
            if(!this.message[type]) return;
            // 如果有订阅,就对这个 `type` 事件做一个轮询 (for 循环)
            this.message[type].forEach(item => {
                // 挨个执行每一个消息的回调函数 callback
                item();
            });
        }
    
        /**
         * $once 只订阅一次
         * @param {*} type 事件名 (事件类型)
         * @param {*} callback 回调函数
         */
        $once(type, callback) {
            let one = (...args) => {
                // 执行发布
                callback(args);
                // 停止订阅
                this.$off(type, one);
            }
            // 注册重构后的一次监听事件
            this.$on(type, one);
        }
    }
    
    
    let ob = new Observer();
    
    let func = function () {
      console.log("我是小刘")
    }
    
    ob.$on("name", func);
    ob.$emit("name");
    // 注销对应的事件
    ob.$off("name", func);
    // 再次触发对应的事件,就不会触发了
    ob.$emit("name");
    
    // 只订阅一次
    ob.$once("name1", function () {
      console.log("我是小李");
    })
    ob.$emit("name1");
    

    相关文章

      网友评论

          本文标题:观察者模式 与 发布订阅模式

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