资讯专栏INFORMATION COLUMN

观察者模式的使用介绍

ityouknow / 2301人阅读

摘要:观察者模式介绍观察者模式又称发布订阅模式,它定义对象间的一种一对多的依赖关系,当一个对象发生改变的时候,所依赖它的对象都能得到通知。关于内部的观察者模式可以参数这篇文档。总结总之,观察者模式在中的使用是非常广泛的。

javascript观察者模式 介绍

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

特点

发布 & 订阅

一对多

优点

低耦合,观察者和观察目标都是抽象出来,容易扩展和重用

触发(通讯)机制,由观察目标通知所有观察它的人

缺点

一个观察目标下可能存在很多的观察者,那么当观察目标需要通知所有观察者的时候会花很多时间

观察者和观察目标之间如果存在依赖的话,可能会发生循环调用,进入死循环导致系统崩溃

观察者模式没有相应的机制让观察者知道观察目标是如何发生变化,仅仅知道观察目标发生了变化

观察目标可能将一些无用的更新发送出去

简单例子

例子:A,B,C三个人都关注了某一个电台,当电台发布新内容的时候通知A,B,C三个人。

构思:具体的构思中,我们可以知道电台作为发布者,它有了新的内容,需要向ABC这三个订阅者推送他的最新的消息。那么我们就可以知道电台这个发布者需要包含新的更新内容以及有哪些订阅者订阅了它。

代码实现:
简单的代码实现:

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("十一月份最新原创歌单发布了");

解读:

抽象了一个发布者(Radio),它有更新内容(setState)、添加订阅者(addObserver)、以及触发所有订阅者(notifyingObservers);

抽象了一个订阅者(People),他有自己的个人信息(如:name),以及接受到通知后所需要执行的动作(updata);

当我们每次更新消息的时候出发notifyingObservers方法,将所有的observersupdate都触发了

当然,实际上,我们上的每一个订阅者都有这个update,当这个update不满足功能需求的时候,我们同样可以将实例出来的订阅者多带带设置update; 如:

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

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

场景延伸

网页页面事件

代码案例:



解读:可以理解成函数订阅了$("#btn")的click事件,当$("#btn")的click被我们点击触发,函数收到触发信息,并自执行。 那么这个函数就是观察者(订阅者),$("#btn")的click事件就是观察目标(发布者)。

Promise

代码案例:

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。

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中见过这样的页面事件写法:

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

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

总结

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99005.html

相关文章

  • RxJava系列二(基本概念及使用介绍

    摘要:作用默认的,直接在当前线程运行总是开启一个新线程用于密集型任务,如异步阻塞操作,这个调度器的线程池会根据需要增长对于普通的计算任务,请使用默认是一个,很像一个有线程缓存的新线程调度器计算所使用的。这个使用的固定的线程池,大小为核数。 转载请注明出处:https://zhuanlan.zhihu.com/p/20687307 RxJava系列1(简介) RxJava系列2(基本概念及使...

    Profeel 评论0 收藏0
  • php设计模式

    摘要:我们今天也来做一个万能遥控器设计模式适配器模式将一个类的接口转换成客户希望的另外一个接口。今天要介绍的仍然是创建型设计模式的一种建造者模式。设计模式的理论知识固然重要,但 计算机程序的思维逻辑 (54) - 剖析 Collections - 设计模式 上节我们提到,类 Collections 中大概有两类功能,第一类是对容器接口对象进行操作,第二类是返回一个容器接口对象,上节我们介绍了...

    Dionysus_go 评论0 收藏0
  • php设计模式

    摘要:我们今天也来做一个万能遥控器设计模式适配器模式将一个类的接口转换成客户希望的另外一个接口。今天要介绍的仍然是创建型设计模式的一种建造者模式。设计模式的理论知识固然重要,但 计算机程序的思维逻辑 (54) - 剖析 Collections - 设计模式 上节我们提到,类 Collections 中大概有两类功能,第一类是对容器接口对象进行操作,第二类是返回一个容器接口对象,上节我们介绍了...

    vspiders 评论0 收藏0
  • 察者模式到迭代器模式系统讲解 RxJS Observable(一)

    摘要:是的缩写,起源于,是一个基于可观测数据流结合观察者模式和迭代器模式的一种异步编程的应用库。是基于观察者模式和迭代器模式以函数式编程思维来实现的。学习之前我们需要先了解观察者模式和迭代器模式,还要对流的概念有所认识。 RxJS 是 Reactive Extensions for JavaScript 的缩写,起源于 Reactive Extensions,是一个基于可观测数据流 Stre...

    notebin 评论0 收藏0

发表评论

0条评论

ityouknow

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<