概念
一种一对多的关系,多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象
解决的问题
- 需要定义对象之间的一对多依赖关系,而不使对象之间紧密耦合。
- 当一个对象改变状态时,需要自动更新一组依赖对象。
需要注意的问题
内存泄漏(已过期的监听器问题)
在观察者模式的基本实现中,当观察者注册到主题时,主题保留了对观察者的引用,以便在状态变化时通知它们。但如果在后续的使用中,没有正确注销(取消注册)观察者,那么这些观察者对象将保持活动状态,无法被垃圾回收器回收,从而导致内存泄漏。
显示注册
// 创建主题对象
class Subject {
constructor() {
this.observers = []; // 观察者列表
}
// 注册观察者
registerObserver(observer) {
this.observers.push(observer);
}
// 注销观察者
unregisterObserver(observer) {
const index = this.observers.indexOf(observer);
if (index !== -1) {
this.observers.splice(index, 1);
}
}
// 通知观察者状态变化
notifyObservers() {
for (const observer of this.observers) {
observer.update();
}
}
}
// 创建观察者对象
class Observer {
constructor() {
// ...
}
// 观察者的更新操作
update() {
// ...
}
}
// 使用强引用创建主题和观察者
const subject = new Subject();
const observer = new Observer();
// 注册观察者到主题
subject.registerObserver(observer);
// 当主题状态发生变化时,通知观察者
subject.notifyObservers();
// 有一天突然不想要这个观察者了
// 忘记注销观察者/没有注销观察者的方法
// 然后就寄了
当使用弱引用时,对象之间的引用关系是非强制性的,即当没有其他强引用指向对象时,对象可能会被垃圾回收器回收。以下是使用弱引用的JavaScript示例代码:
// 使用 WeakMap 创建主题对象
class Subject {
constructor() {
this.observers = new WeakMap(); // 使用 WeakMap 存储观察者
}
// 注册观察者
registerObserver(observer) {
this.observers.set(observer, true);
}
// 通知观察者状态变化
notifyObservers() {
for (const observer of this.observers.keys()) {
observer.update();
}
}
}
// 创建观察者对象
class Observer {
constructor() {
// ...
}
// 观察者的更新操作
update() {
// ...
}
}
// 使用弱引用创建主题和观察者
const subject = new Subject();
const observer = new Observer();
// 注册观察者到主题
subject.registerObserver(observer);
// 当主题状态发生变化时,通知观察者
subject.notifyObservers();
无响应
在模型状态频繁更新的情况下。频繁的更新可能导致视图变得不响应(例如,调用了许多重绘方法),这时观察者应该整个节流。
// 创建主题对象
class Subject {
constructor() {
this.observers = []; // 观察者列表
this.timerId = null; // 定时器ID
}
// 注册观察者
registerObserver(observer) {
this.observers.push(observer);
}
// 通知观察者状态变化
// 整个节流
notifyObservers() {
if (!this.timerId) {
this.timerId = setTimeout(() => {
for (const observer of this.observers) {
observer.update();
}
this.timerId = null; // 清空定时器ID
}, 1000); // 设置一个1秒的间隔,控制视图更新频率
}
}
}
// 创建观察者对象
class Observer {
constructor() {
// ...
}
// 观察者的更新操作
update() {
// ...
}
}
const subject = new Subject();
const observer = new Observer();
subject.registerObserver(observer);
// 模拟频繁的状态更新
setInterval(() => {
subject.notifyObservers();
}, 100); // 每100毫秒更新一次状态
异常处理
如果顺序执行的话,只要一个观察者出现错误,就卡住了。唔这方面我只想到了try catch一下,不太知道还有什么别的解决方式。
与之相关的设计模式
发布订阅模式,中介者模式,单例模式.....应该后续会填坑的吧(心虚