天天看点

javascript设计模式_JavaScript设计模式之观察者模式

前言

最近在学习

RxJS

,由于

RxJS

中有两个重要的概念

Observable

Observer

中使用了观察者模式,因此就对该模式学习一遍,顺便对一些常用的设计模式进行了一些了解。虽然平时很少用设计模式,但是设计模式的思想却出现在我们使用的各种框架中,甚至ES6的API中,时刻与我们相伴。学习好JavaScript真的是前路漫漫,还需努力!

本次分享主要包括:

  • 观察者模式简介
  • 观察者模式的使用场景
  • 观察者模式的实现
  • 观察者模式的优缺点

简介

观察者模式又叫作发布—订阅模式,是我们最常用的设计模式之一(其实这两种模式还是存在一定的区别)。它定义了对象间的一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖它的对象都将得到通知和更新。观察者模式提供了一个订阅模型,其中对象订阅事件并在事件发生时得到通知。这种模式是事件驱动的编程基石,它有利于良好的面向对象的设计。

如果上面的描述不是很容易理解,我们举个生活中的例子:拿买房来讲,如果你想买房,但是你看好的楼盘还没有开盘,因此你就将你的电话留给售楼小姐,一旦楼盘推出就让她打电话给你。主动权在售楼方,而你只需要提供一个联系方式,不需要你每天都打电话就能知道楼盘出来了没。楼盘相当于被观察者,你相当于观察者。或者说你是订阅者,订阅了楼盘是否推出这一事件。

学习了

RxJS

后对观察者模式有了更为深刻的理解,观察者本质上就是将数据的产生与数据处理的逻辑相分离,被观察者负责数据的产生,观察者负责处理数据,即产生的数据流与处理数据的逻辑分离开来。

使用场景

[1] DOM事件

实际上,只要我们曾经在DOM节点上绑定过事件函数,那我们就使用过观察者模式,因为JS和DOM之间就是实现了一种观察者模式。

document.body.addEventListener("click", function() {    alert("Hello World")},false )document.body.click() //模拟用户点击
           

上面代码中,需要监听用户点击document.body的动作,但是我们没有办法预知用户将在什么时候点击。因此我们订阅了document.body的click事件,当body节点被点击时,body节点便会向订阅者发布"Hello World"消息。

[2] Vue中watch

javascript设计模式_JavaScript设计模式之观察者模式

watch方法就是监听的data中firstName和lastName,当数据发生变化,就会通知到watch中的两个方法,执行相应的改变。

[3] NodeJs中http请求

javascript设计模式_JavaScript设计模式之观察者模式

http读取数据流,由于是分片读取,我们无法预知数据流什么时候读取完成,因此我们订阅了end事件,当数据流读取完成后,就会发布读取完成的消息,从而进行下一步生成页面的操作。

当然了还有很多例子,比如ES6中的Promise、Vue和React中的生命周期函数等,就不一一列举了。

实现

观察者模式是对象间一种一对多的关系,有发布和订阅两种模式,在实现之前我们先画一个类图:

javascript设计模式_JavaScript设计模式之观察者模式

其中Observer是观察者,Subject是被观察到对象。观察者中有被观察者的引用。被观察者中有存放了观察者的数组,并有添加观察者和通知观察者的两个方法。

具体实现如下:

// 被观察者class Subject {    constructor() {        this.state = 0;        this.observers = [];    }    getState() {        return this.state;    }    setState(state) {        this.state = state;        this.notifyAllObservers();    }    notifyAllObservers() {        this.observers.forEach(observer => {            observer.update()        })    }    attach(observer) {        this.observers.push(observer)    }}// 观察者class Observer {    constructor(name, subject) {        this.name = name;        this.subject = subject;        this.subject.attach(this);    }    update() {        console.log(`${this.name} update, state ${this.subject.getState()}`)    }}// 测试代码let s = new Subject();let o1 = new Observer('o1', s);let o2 = new Observer('o2', s);let o3 = new Observer('o3', s);s.setState(1);
           

本例中实现的是监听被观察者

state

的变化,被观察者执行了

setState

的方法时,所有的观察者就行了各自的

update

方法。

优点与不足

观察者模式的优点非常明显:一是时间上的解耦,二是对象之间的解耦。既可用于异步编程中,也可以用帮助我们完成更松耦合的代码编写。但它仍然有所不足:

  • 创建订阅者本身要消耗一定的时间和内存
  • 当订阅一个消息时,也许此消息并没有发生,但这个订阅者会始终存在内存中。
  • 观察者模式弱化了对象之间的联系,这本是好事情,但如果过度使用,对象与对象之间的联系也会被隐藏的很深,会导致项目的难以跟踪维护和理解。

小结

本次分享介绍了观察者模式,举例说明了观察者模式在我们身边的应用。通过创建

Observer

Subject

两个类实现了观察者模式,作为一个简单的参考方便以后在我们的业务场景中使用。最后介绍了观察者模式的优缺点,在选择使用观察者模式的时候作为一个提醒。本次分享如果有误,还请大家批评指正!

继续阅读