备注:本文所有代码采用ES6书写。
什么是观察者模式?
观察者模式是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。
以上是维基百科对于观察者模式的定义。其实上面这段话不难理解,打个比方。双十一之前,你看上了一个腿打折的商品需要预约,系统会在双十一的时候提醒所有点了预约的用户来抢货。
我们来解析一下这个过程。系统就可以看做是目标对象;而你预约的这个动作就是向目标对象进行注册,你就是目标对象其中的一个观察者;双十一系统主动提醒你抢货,是因为到了系统放货的时间,所以提醒了包括你在内的所有点了预约的人来抢货,也就是说它本身的状态(到了放货的时间)发生了改变主动对所有用户发出了通知。
说了这么多,还是来实现一个基础版本的代码吧。
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('do something');
}
}
const sub = new Subject(); /* 系统 */
sub.add(new Observer()); /* 张三点了预约 */
sub.add(new Observer()); /* 李四点了预约 */
sub.notify(); /* 双十一了,通知所有点了预约的人来抢货了 */
什么是发布订阅模式?
其实最开始发布订阅只是观察者的一个别称,不过后面慢慢的它发展出自己的风格来了。同样的来看看维基百科上的定义。
在软件架构中,发布-订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在。同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者(如果有的话)存在。
其实从定义中我们就可以看出来,发布订阅模式发布者和观察者是没有直接接触的,中间其实是多了一个"中间商"。举个例子,当你想买房的时候,一般会去找中介,中介会把你的需求进行一个归类,当出现一个合适的房源的时候,中介会通知所有想购买这类房子的人来看房,而买卖双方其实是不能直接接触的。
同样的,还是实现一个简单的代码。
class SubPub {
constructor() {
this.observers = {};
}
subscribe(topic, callback) {
if (!this.observers[topic]) {
this.observers[topic] = [];
}
this.observers[topic].push(callback);
}
publish(topic, ...args) {
let callbacks = this.observers[topic] || [];
callbacks.forEach(cb => cb.call(this, ...args));
}
}
const subject = new SubPub(); /* 中介 */
subject.subscribe('两室一厅', () => { console.log('张三'); }); /* 张三想买一个两室一厅的房子 */
subject.subscribe('三室一厅', () => { console.log('李四') }); /* 李四想买一个三室一厅的房子 */
subject.subscribe('两室一厅', () => { console.log('王五'); }); /* 王五想买一个两室一厅的房子 */
subject.publish('两室一厅'); /* 当出现一个两室一厅的房子时,中介会通知张三和王五来看房 */
区别与联系
- 观察者通信双方是明确知道对方的存在,发布订阅是通过一个消息中心进行代理。
- 观察者的代码是高耦合的。
- 观察者的代码是同步的,而发布订阅由于存在一个消息中心,所以多是异步的。
从我们实现代码也可以看出来,其实观察者和发布订阅最大的区别就是消息的两个主体是否知道对方,是否通过代理的方式进行消息通信(即有无中间商赚差价)。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。