观察者模式和发布订阅模式(上)
程序员文章站
2022-06-21 10:28:43
观察者模式 定义:观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。 其中有两个定义需要明确,被观察者和观察者。通常来说,这两者是一对多的,也有多对多的情景。 在网页开发中,被观察者通常是数据源,不论 ......
观察者模式
定义:观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。
其中有两个定义需要明确,被观察者和观察者。通常来说,这两者是一对多的,也有多对多的情景。
在网页开发中,被观察者通常是数据源,不论是内存数据,还是持久化数据,又或者是接口返回的数据,都可以作为被观察者。它一旦改变,就去改变依赖于它的节点。
观察者有很多可能,针对于网页开发,我们常常认为dom节点是观察者,一旦节点的监视的数据源发生变化,节点也执行更新方法。当然不限于此,也有可能是一个事件,一次计数等等。
接下来用js写一个简单的观察者模式的例子:
// 发布类 class Subject { constructor (data) { this.obList = []; this.data = data; } add (ob) { if (arguments.length >= 1) { Array.from(arguments).forEach(item => this.obList.push(item)); } } remove (ob) { let i = this.obList.findIndex(ele => ele === ob); if (i >= 0) { this.obList.splice(i, 1); } } notify () { this.obList.forEach((item) => { item.update(this.data); }) } } // 观察者类 class Observer { constructor (id) { this.id = id; } update (data) { console.log('observer ' + this.id + ': ' + data + ';'); } } function test() { let sub = new Subject('test'); let ob1 = new Observer(1); let ob2 = new Observer(2); let ob3 = new Observer(3); sub.add(ob1, ob2, ob3); sub.notify(); sub.remove(ob2); sub.notify(); } test();
结果为:
observer 1: test; observer 2: test; observer 3: test; observer 1: test; observer 3: test;
这里简单定义了一个发布类和一个观察类,发布者维护一个观察者列表,每次数据变化后,依次通知所有在观察者列表里的观察者。
代码很简单,可以执行在控制台或者node里跑一下。
但是这样的耦合很深,观察者和发布者不能有其他的表现,很死板,我们可以继续抽象一下。
先画个类图:
借助于TypeScript,我们可以有如下的发布者和观察者定义。
abstract class Observer { abstract update(); } abstract class Subject { protected obList: ObserverList; abstract notify(); }
ObserverList则可以实现如下:
class ObserverList { private list: Array<Observer>; constructor () { this.list = []; } add (ob: Observer) { this.list.push(ob); } remove (ob: Observer) { if (this.list.indexOf(ob) > -1) { this.list.splice(this.list.indexOf(ob), 1); } } empty () { this.list = []; } public each () { this.list.forEach(item => { item.update(); }) } }
接下来实现两个实体类:
// 实体发布类 class ConcreteSubject extends Subject { protected obList = new ObserverList(); private _data: string; constructor (defaultData: string) { super(); this._data = defaultData; } set data (newVaule) { this._data = newVaule; } get data () { return this._data; } add (ob: Observer) { this.obList.add(ob); } remove (ob: Observer) { this.obList.remove(ob); } notify () { this.obList.each() } } // 可以指定发布者的观察者类 class ConcreteObserver extends Observer { readonly _id; private sub; constructor (id, sub) { super(); this._id = id; this.sub = sub; } get id () { return this._id; } update () { console.log('concrete observer ' + this.id + ': ' + this.sub.data); } }
跑一下测试代码:
let sub = new ConcreteSubject('test'); let ob1 = new ConcreteObserver(1, sub); let ob2 = new ConcreteObserver(2, sub); let ob3 = new ConcreteObserver(3, sub); sub.add(ob1) sub.add(ob2) sub.add(ob3) sub.notify();
上面的发布类,使用add、remove等方法来处理观察者列表,通过notify方法,则去通知观察者们,可以去执行update方法了。
观察者和被观察者,仍然耦合比较深,所以又有人提出来发布订阅模式,维护一个事件中心,来处理多个观察者和被观察者的关系,不让他们直接耦合在一起。下一篇对发布订阅做解析。
上一篇: 说个不作不死的事
推荐阅读
-
js发布/订阅模式代码教程
-
JavaScript事件发布/订阅模式原理与用法分析
-
JavaScript实现与使用发布/订阅模式详解
-
wpf 单例模式和异常处理 (原发布 csdn 2017-04-12 20:34:12)
-
使用EventBus + Redis发布订阅模式提升业务执行性能(下)
-
RabbitMQ指南之三:发布/订阅模式(Publish/Subscribe)
-
[JS设计模式]:观察者模式(即发布-订阅者模式)(4)
-
C/S模式,发布/订阅模式和PUSH/PULL模式(上)
-
[js高手之路]设计模式系列课程-发布者,订阅者重构购物车的实例
-
JavaScript设计模式之观察者模式(发布订阅模式)原理与实现方法示例