zoukankan      html  css  js  c++  java
  • js设计模式之【观察者模式】VS【发布/订阅模式模式】的区别?

     两种模式存在一定区别

    一、观察者模式(Observer)

          观察者模式指的是一个对象(Subject)维持一系列依赖于它的对象(Observer),当有关状态发生变更时 Subject 对象则通知一系列 Observer 对象进行更新。

          在观察者模式中,Subject 对象拥有添加、删除和通知一系列 Observer 的方法等等,而 Observer 对象拥有更新方法等等。

    // 定义一个主体对象
    class Subject {
      constructor() {
        this.Observers = [];
      }
      add(observer) { //添加
        this.Observers.push(observer)
      }
      remove(observer) {//移除
        this.Observers.filter(item => item === observer);
      }
      notify() {
        this.Observers.forEach(item => {
          item.update();
        })
      }
    }
    //定义观察着对象
    class Observer {
      constructor(name) {
        this.name = name;
      }
      update() {
        console.log(`my name is:${this.name}`);
      }
    }
    
    //测试
    let sub = new Subject();
    let obs1 = new Observer('leaf111');
    let obs2 = new Observer('leaf222');
    sub.add(obs1);
    sub.add(obs2);
    sub.notify();

        上述代码中,我们创建了 Subject 对象和两个 Observer 对象,当有关状态发生变更时则通过 Subject 对象的 notify 方法通知这两个 Observer 对象,这两个 Observer 对象通过 update 方法进行更新。

    二、发布订阅模式(Publisher && Subscriber)

          发布订阅模式指的是希望接收通知的对象(Subscriber)基于一个主题通过自定义事件订阅主题,被激活事件的对象(Publisher)通过发布主题事件的方式通知各个订阅该主题的 Subscriber 对象。

          

    let pubSub = {
      subs: [],
      subscribe(key, fn) { //订阅
        if (!this.subs[key]) {
          this.subs[key] = [];
        }
        this.subs[key].push(fn);
      },
      publish(...arg) {//发布
        let args = arg;
        let key = args.shift();
        let fns = this.subs[key];
    
        if (!fns || fns.length <= 0) return;
    
        for (let i = 0, len = fns.length; i < len; i++) {
          fns[i](args);
        }
      },
      unSubscribe(key) {
        delete this.subs[key]
      }
    }
    
    //测试
    pubSub.subscribe('name', name => {
      console.log(`your name is ${name}`);
    })
    pubSub.subscribe('gender', gender => {
      console.log(`your name is ${gender}`);
    })
    pubSub.publish('name', 'leaf333');  // your name is leaf333
    pubSub.publish('gender', '18');  // your gender is 18
    

     

    三、区别 

     如上图所示:

           1、在观察者模式中,观察者是知道Subject的,Subject一直保持对观察者进行记录。然而,在发布订阅模式中,发布者和订阅者不知道对方的存在。它们只有通过消息代理进行通信。

           2、在发布订阅模式中,组件是松散耦合的,正好和观察者模式相反。 

           3、观察者模式大多数时候是同步的,比如当事件触发,Subject就会去调用观察者的方法。而发布-订阅模式大多数时候是异步的(使用消息队列)。
     

    四、vue中的作用

          Vue会遍历实例的data属性,把每一个data都设置为访问器,然后在该属性的getter函数中将其设为watcher,在setter中向其他watcher发布改变的消息。

       //遍历传入实例的data对象的属性,将其设置为Vue对象的访问器属性
        function observe(obj,vm){
            Object.keys(obj).forEach(function(key){
                defineReactive(vm,key,obj[key]);
            });
        }
        //设置为访问器属性,并在其getter和setter函数中,使用订阅发布模式。互相监听。
        function defineReactive(obj,key,val){
            //这里用到了观察者模式,它定义了一种一对多的关系,让多个观察者监听一个主题对象,这个主题对象的状态发生改变时会通知所有观察者对象,观察者对象就可以更新自己的状态。
            //实例化一个主题对象,对象中有空的观察者列表
            var dep = new Dep();
            //将data的每一个属性都设置为Vue对象的访问器属性,属性名和data中相同
            //所以每次修改Vue.data的时候,都会调用下边的get和set方法。然后会监听v-model的input事件,当改变了input的值,就相应的改变Vue.data的数据,然后触发这里的set方法
            Object.defineProperty(obj,key,{
                get: function(){
                    //Dep.target指针指向watcher,增加订阅者watcher到主体对象Dep
                    if(Dep.target){
                        dep.addSub(Dep.target);
                    }
                    return val;
                },
                set: function(newVal){
                    if(newVal === val){
                        return
                    }
                    val = newVal;
                    //console.log(val);
                    //给订阅者列表中的watchers发出通知
                    dep.notify();
                }
            });
        }
    
        //主题对象Dep构造函数
        function Dep(){
            this.subs = [];
        }
        //Dep有两个方法,增加订阅者  和  发布消息
        Dep.prototype = {
            addSub: function(sub){
                this.subs.push(sub);
            },
            notify: function(){
                this.subs.forEach(function(sub){
                    sub.update();
                });
            }
        }
    

      

  • 相关阅读:
    WebService帮助类改良版,支持多webservice
    .NET-list扩展方法Distinct去重
    C#创建泛型类T的实例的三种方法
    划水网站
    DataGridView增加右键取消操作
    Sql Server 快捷键
    SQL Server中使用convert进行日期转换
    ToolStrip 选中某一项打勾
    H5实现手写功能
    git使用
  • 原文地址:https://www.cnblogs.com/leaf930814/p/9014200.html
Copyright © 2011-2022 走看看