概念
观察者模式
在观察者模式中,只有两种主体:目标对象 (Subject) 和 观察者 (Observer)。
-
目标对象
Subject:- 维护观察者列表
observers - 定义添加、移除观察者的方法
- 当
Subject调用Subject.notify是会执行observers数组的回调
- 维护观察者列表
-
观察者
Observer需要实现update方法,供Subject调用。
发布-订阅模式
- 发布 ——
Publisher - 中介 ——
EventChannel- 维护任务类型,以及每种任务下的订阅情况
- 给订阅者提供订阅功能 ——
subscribe功能 - 给发布者提供发布动能 ——
publish功能
- 订阅 ——
Subscriber
一、观察者模式
// 定义主题类
class Subject {
constructor() {
// 观察者list
this.observers = [];
console.log('Subject created');
}
// 增加观察者
addObserver(observer) {
console.log('Observer.add invoked');
this.observers.push(observer);
}
// 移除观察者
removeObserver(observer) {
console.log('Observer.remove invoked');
this.observers.forEach((item, i) => {
if (item === observer) {
this.observers.splice(i, 1);
}
});
}
// 通知所有观察者
notify(...arg) {
console.log('Subject.notify invoked');
this.observers.forEach((observer) => {
observer.update(...arg);
});
}
}
// 定义观察者类
class Observer {
constructor() {
console.log('Observer created');
}
update(...arg) {
console.log('arg:', arg);
console.log('Observer.update invoked');
}
}
// 创建主题
const subject = new Subject();
// 创建观察者
const observer = new Observer();
// 主题添加观察者
subject.addObserver(observer);
// 主题通知观察者
subject.notify('notify...');
二、发布-订阅模式
事件调度中介
class EventChannel {
constructor() {
// 事件中心
this.events = {};
}
// 订阅事件
subscribe(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(callback);
}
// 发布事件
publish(eventName, ...args) {
if (this.events[eventName]) {
// 这里需要对 this.events[eventName] 做一次浅拷贝,主要目的是为了避免通过 once 安装的监听器在移除的过程中出现顺序问题
const events = this.events[eventName].slice();
events.forEach((callback) => {
callback(...args);
});
}
}
// 取消订阅
unSubscribe(eventName, callback) {
const callbacks = this.events[eventName];
const index = callbacks.indexOf(callback);
if (index !== -1) {
callbacks.splice(index, 1);
}
}
// 当次订阅
subscribeOnce(eventName, callback) {
// 对回调函数进行包装,使其执行完毕自动被移除
const wrapper = (...args) => {
callback(...args);
this.unSubscribe(eventName, wrapper);
};
this.subscribe(eventName, wrapper);
}
}
1.生成事件频道
const eventChannel = new EventChannel();
2.创建订阅
// 创建订阅event-test
eventChannel.subscribe('event-test', () => {
console.log('event-test1');
});
// 创建订阅event-prew
eventChannel.subscribe('event-prew', () => {
console.log('event-prew1');
});
3.发布事件
// 发布事件
eventChannel.publish('event-prew');
总结
从表面上看:
- 观察者模式里,只有两个角色 —— 观察者 + 被观察者
- 而发布-订阅模式里,不仅仅只有发布者和订阅者两个角色,还有一个中介角色(
EventChannel)
往更深层次讲:
- 观察者和被观察者,是松耦合的关系
- 发布者和订阅者,则完全不存在耦合
从使用层面上讲:
- 观察者模式,多用于单个应用内部
- 发布订阅模式,则更多的是一种跨应用的模式(cross-application pattern),比如我们常用的消息中间件