为了账号安全,请及时绑定邮箱和手机立即绑定

观察者模式和发布订阅模式(上)

标签:
JavaScript

观察者模式

定义:观察者模式(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

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消