观察者模式的使用介绍

javascript观察者模式

介绍

观察者模式又称发布-订阅模式,它定义对象间的一种一对多的依赖关系,当一个对象发生改变的时候,所依赖它的对象都能获得通知。例如:咱们订阅了一个栏目,当栏目有新文章的时候,它会自动通知全部订阅它的人。javascript

特色

  • 发布 & 订阅
  • 一对多

优势

  • 低耦合,观察者和观察目标都是抽象出来,容易扩展和重用
  • 触发(通信)机制,由观察目标通知全部观察它的人

缺点

  • 一个观察目标下可能存在不少的观察者,那么当观察目标须要通知全部观察者的时候会花不少时间
  • 观察者和观察目标之间若是存在依赖的话,可能会发生循环调用,进入死循环致使系统崩溃
  • 观察者模式没有相应的机制让观察者知道观察目标是如何发生变化,仅仅知道观察目标发生了变化
  • 观察目标可能将一些无用的更新发送出去

简单例子

  • 例子:A,B,C三我的都关注了某一个电台,当电台发布新内容的时候通知A,B,C三我的。
  • 构思:具体的构思中,咱们能够知道电台做为发布者,它有了新的内容,须要向ABC这三个订阅者推送他的最新的消息。那么咱们就能够知道电台这个发布者须要包含新的更新内容以及有哪些订阅者订阅了它。
  • 代码实现:
    简单的代码实现:html

    class Radio {
      constructor() {
        this.state = 0;
        this.observers = [];
      }
    
      setState(state) {
        this.state = state;
        this.notifyingObservers();
      }
    
      addObserver(observer) {
        this.observers.push(observer);
      }
    
      notifyingObservers() {
        const state = this.state;
        this.observers.forEach(observer => {
          observer.update(state);
        });
      }
    }
    
    class People {
      constructor(name) {
        this.name = name;
      }
    
      update(content) {
        console.log(`我是${this.name},我接受到更新了,更新内容:${content}`);
      }
    }
    
    // 建立订阅者
    const peopleA = new People('小A');
    const peopleB = new People('小B');
    const peopleC = new People('小C');
    
    // 添加发布者
    const radio = new Radio();
    
    // 订阅
    radio.addObserver(peopleA);
    radio.addObserver(peopleB);
    radio.addObserver(peopleC);
    
    // 发布者发布
    radio.setState('十月份最热歌单发布了');
    radio.setState('十一月份最新原创歌单发布了');
  • 解读:
  1. 抽象了一个发布者(Radio),它有更新内容(setState)、添加订阅者(addObserver)、以及触发全部订阅者(notifyingObservers);
  2. 抽象了一个订阅者(People),他有本身的我的信息(如:name),以及接受到通知后所须要执行的动做(updata);
  3. 当咱们每次更新消息的时候出发notifyingObservers方法,将全部的observersupdate都触发了

固然,实际上,咱们上的每个订阅者都有这个update,当这个update不知足功能需求的时候,咱们一样能够将实例出来的订阅者单独设置update; 如:java

peopleA.update = function(content) {
    // 新代码
  }

以上就是一个简单的观察者模式的例子node

场景延伸

  1. 网页页面事件
  • 代码案例:react

    <button id="btn">点击</button>
    
    <script>
      $('#btn').click(function() {
          console.log('btn被点击');
      })
    </script>
  • 解读:能够理解成函数订阅了$('#btn')的click事件,当$('#btn')的click被咱们点击触发,函数收到触发信息,并自执行。 那么这个函数就是观察者(订阅者),$('#btn')的click事件就是观察目标(发布者)。
  1. Promise
  • 代码案例:git

    function loadImage(url) {
      return new Promise(function(resolve, reject) {
        let image = document.createElement('img');
        image.onload = function () {
          resolve(image);
        }
        image.onerror = function () {
          reject('图片加载失败');
        }
        image.src = url;
      });
    }
    const src = 'http://imgsrc.baidu.com/image/c0%3Dpixel_huitu%2C0%2C0%2C294%2C40/sign=ad13ee4af0f2b211f0238d0ea3f80054/2e2eb9389b504fc26849383ceedde71190ef6df1.jpg'
    const img = loadImage(src);
    img.then(function (img) {
      console.log('width', img.width);
      return img
    }).then(function (img) {
      console.log('height', img.height);
    });
  • 解读:promise的resolve是then的执行者,当promise的状态发生改变后(resolve的时候状态从”未完成“变为”成功“),一一执行then下的方法,那么这些then能够说是promise的观察者,当这个promise被resolve的时候,全部的观察获得了通知。
  • 关于promise内部的观察者模式能够参数https://github.com/xieranmaya/blog/issues/3这篇文档。

promise.then会把内部的函数添加到一个callback的数组内,等异步执行完成以后在进行一次调用该函数。每个.then会返回一个新的promise。github

  1. js的事件触发器(自定义事件)
  • 代码案例:数组

    class EventEmitter() {
      constructor() {
        this.events = {};
      }
    
      // 订阅事件
      on(type, listener) {
        if (!this.events) { this.events = Object.create(null); }
    
        if (this.events[type]) {
          this.events[type].push(listener)
        } else {
          this.events[type] = [listener];
        }
      }
    
      // 触发执行
      emit(type, ...args) {
        if (this.events[type]) {
          this.events[type].forEach(fn => fn.call(this, ...args));
        }
      }
    
      // 解绑
      off(type, listener) {
        id (this.events[type]) {
          this.events[type] = this.events[type].filter(fn => {
            return fn !== listener;
          });
        }
      }
    }
    
    const myEmitter = new EventEmitter();
    myEmitter.on('log', function() {console.log('111111')});
    myEmitter.emit('log');
  • 解读:这个就和第一个案例有点类似,咱们在jq中见过这样的页面事件写法:promise

    $('id').on('click', function() {
      // 事件代码
    });

    这个就是一种事件触发器,在nodejs里面大量采用了事件触发器的方法。详情能够去看nodejs里面的EventEmitter方法,就能够大致理解他的机制了。
    同理,咱们也能够明白react里面的生命周期等mvvm框架,里面大量采用了观察者模式。它们都是定义了一个个钩子,等状态达到的时候我就触发相对应的钩子,执行相对应的代码。框架

总结

总之,观察者模式在javascript中的使用是很是普遍的。其低耦合的特色方便在多人开发的复杂项目中,能提升效率,使代码的维护性大大提高。

相关文章
相关标签/搜索