观察者模式与订阅发布模式的区别 发布/订阅模式、 观察者模式在Vue中的应用场景

1、观察者模式
观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新。观察者模式属于行为型模式,行为型模式关注的是对象之间的通讯,观察者模式就是观察者和被观察者之间的通讯。

观察者模式有一个别名叫“发布-订阅模式”,或者说是“订阅-发布模式”,订阅者和订阅目标是联系在一起的,当订阅目标发生改变时,逐个通知订阅者。我们可以用报纸期刊的订阅来形象的说明,当你订阅了一份报纸,每天都会有一份最新的报纸送到你手上,有多少人订阅报纸,报社就会发多少份报纸,报社和订报纸的客户就是上面文章开头所说的“一对多”的依赖关系。

2、订阅-发布模式
其实24种基本的设计模式中并没有发布订阅模式,上面也说了,他只是观察者模式的一个别称。

但是经过时间的沉淀,似乎他已经强大了起来,已经独立于观察者模式,成为另外一种不同的设计模式。

在现在的发布订阅模式中,称为发布者的消息发送者不会将消息直接发送给订阅者,这意味着发布者和订阅者不知道彼此的存在。在发布者和订阅者之间存在第三个组件,称为调度中心或事件通道,它维持着发布者和订阅者之间的联系,过滤所有发布者传入的消息并相应地分发它们给订阅者。

举一个例子,你在微博上关注了A,同时其他很多人也关注了A,那么当A发布动态的时候,微博就会为你们推送这条动态。A就是发布者,你是订阅者,微博就是调度中心,你和A是没有直接的消息往来的,全是通过微博来协调的(你的关注,A的发布动态)。

3、两种模式的区别
我们先来看下这两个模式的实现结构:

可以看出,发布订阅模式相比观察者模式多了个事件通道,事件通道作为调度中心,管理事件的订阅和发布工作,彻底隔绝了订阅者和发布者的依赖关系。即订阅者在订阅事件的时候,只关注事件本身,而不关心谁会发布这个事件;发布者在发布事件的时候,只关注事件本身,而不关心谁订阅了这个事件。

观察者模式有两个重要的角色,即目标和观察者。在目标和观察者之间是没有事件通道的。一方面,观察者要想订阅目标事件,由于没有事件通道,因此必须将自己添加到目标(Subject) 中进行管理;另一方面,目标在触发事件的时候,也无法将通知操作(notify) 委托给事件通道,因此只能亲自去通知所有的观察者。

我们再来看一下这两个模式的代码实现:

订阅-发布模式

class PubSub {
    constructor() {
        this.subscribers = [];
    }
     
    subscribe(topic, callback) {
        let callbacks = this.subscribers[topic];
        if (!callbacks) {
            this.subscribers[topic] = [callback];
        } else {
            callbacks.push(callback);
        }
    }
     
    publish(topic, ...args) {
        let callbacks = this.subscribers[topic] || [];
        callbacks.forEach(callback => callback(...args));
    }
}
 
// 创建事件调度中心,为订阅者和发布者提供调度服务
let pubSub = new PubSub();
// A订阅了SMS事件(A只关注SMS本身,而不关心谁发布这个事件)
pubSub.subscribe('SMS', console.log);
// B订阅了SMS事件
pubSub.subscribe('SMS', console.log);
// C发布了SMS事件(C只关注SMS本身,不关心谁订阅了这个事件)
pubSub.publish('SMS', 'I published `SMS` event');

观察者模式

class Subject {
    constructor() {
        this.observers = [];
    }
 
    add(observer) {
        this.observers.push(observer);
    }
 
    notify(...args) {
        this.observers.forEach(observer => observer.update(...args));
    }
}
 
class Observer {
    update(...args) {
        console.log(...args);
    }
}
 
// 创建观察者ob1
let ob1 = new Observer();
// 创建观察者ob2
let ob2 = new Observer();
// 创建目标sub
let sub = new Subject();
// 目标sub添加观察者ob1 (目标和观察者建立了依赖关系)
sub.add(ob1);
// 目标sub添加观察者ob2
sub.add(ob2);
// 目标sub触发SMS事件(目标主动通知观察者)
sub.notify('I fired `SMS` event');

从代码实现可以看出,发布-订阅模式是面向调度中心编程的,而观察者模式则是面向目标和观察者编程的。前者用于解耦发布者和订阅者,后者用于耦合目标和观察者,不可同日而语也~

乱七八糟的什么调度中心。
观察者和订阅模式,都有调度中心。
都是循环执行一些回调函数。
这些回调函数都是来自观察者或者订阅者。
只不过,订阅者是,按自定义分类传入回调

subscribe(topic, callback) 

观察者,是一股脑,传入了观察者对象本身

sub.add(ob1);

后续
观察者模式需要把观察者注册到被观察者身上去。通过被观察者自身状态的变化通知观察者自身状态变了。
所以,从这里可以看出。发布跟订阅是没有关系的。完全可以只订阅不发布。或者只发布不订阅都是OK的。但是,观察者模式的观察者跟被观察者之间是有关系的。其实,观察者模式是包含发布订阅模式的。原理都是将待执行的方法存储起来。等到状态变化或者被发布出去的时候遍历存储方法的数组进行方法的执行。

vue中两者的区别

发布/订阅模式和观察者模式通常被混为一谈,但它们在Vue中有着不同的应用场景。

发布/订阅模式核心:

  • 订阅者
  • 发布者
  • 信号中心(事件中心)
    我们假定:存在一个“信号中心”,某个任务执行完成,就向信号中心“发布”一个信号,其它任务可以向信号中心“订阅”(subscribe)这个信号,从而知道什么时候可以开始执行,这就是发布/订阅模式

发布/订阅模式在Vue中的应用场景:子组件与父组件的通信方式、兄弟组件通信

观察者模式核心:

观察者(Watcher): 每个观察者必须有一个 update() 方法,当事件发生时,执行观察者的update()。观察者可以理解为发布/订阅模式的订阅者。

目标(Dependency依赖):可以理解为发布/订阅模式的发布者

观察者模式在Vue中应用场景:数据实时更新视图:

官方文档:

每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

官方图示:

如何理解:

Vue组件的data并非所有属性都会收集为依赖,而是被模板引用的属性才会收集为依赖,比如< div >{{ msg }}< /div>
当渲染模板时,msg将会触发getter函数,即收集依赖的地点就是在getter中。
在某种情况下对msg进行了重新赋值,那么将会触发setter函数,既然msg改变了,那么视图就要更新了,即通知更新的地点在setter中
如何通知更新?在setter中使用dep的notify方法通知Watcher,即调用观察者的update方法,使得组件重新渲染。

posted @ 2022-07-29 19:08  风意不止  阅读(1879)  评论(0编辑  收藏  举报