观察者模式
定义: 观察者模式 (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 方法了.
观察者和被观察者, 仍然耦合比较深, 所以又有人提出来发布订阅模式, 维护一个事件中心, 来处理多个观察者和被观察者的关系, 不让他们直接耦合在一起. 下一篇对发布订阅做解析.
来源: https://www.cnblogs.com/liuyongjia/p/9404627.html