定义:
观察者模式是一种常用的设计模式,它定义了一种一对多的关系,让多个订阅者对象同时监听某一个主题对象,当主题对象发生变化时,它会通知所有订阅者对象,使它们能够自动更新 。
场景:
- 当一个对象的状态变化需要通知其他多个对象时,可以使用发布订阅模式来实现松耦合的通信
- 当一个事件或消息需要广泛传播或分发给多个接收者时,可以使用发布订阅模式来实现高效的消息分发
- 当一个系统需要支持异步处理或批量处理时,可以使用发布订阅模式来实现事件的延迟触发或批量触发
优点:
1.实现了发布者和订阅者之间的解耦,提高了代码的可维护性和复用性。
2.支持异步处理,可以实现事件的延迟触发和批量处理。
3.支持多对多的通信,可以实现广播和组播的功能。
缺点:
1.可能会造成内存泄漏,如果订阅者对象没有及时取消订阅,就会一直存在于内存中。
2.可能会导致程序的复杂性增加,如果订阅者对象过多或者依赖关系不清晰,就会增加程序的调试难度。
3.可能会导致信息的不一致性,如果发布者在通知订阅者之前或之后发生了变化,就会造成数据的不同步。
具体实现
在JavaScript中,实现发布订阅模式的基本思想是:
1.定义一个发布者对象,它有一个缓存列表,用于存放订阅者对象的回调函数
2.定义一个订阅方法,用于向缓存列表中添加回调函数
3.定义一个取消订阅方法,用于从缓存列表中移除回调函数
4.定义一个发布方法,用于遍历缓存列表,依次执行回调函数,并传递相关参数
// 定义一个发布者对象
var pub = {
// 缓存列表,存放订阅者回调函数
list: {},
// 订阅方法
subscribe: function(key, fn) {
// 如果没有该消息的缓存列表,就创建一个空数组
if (!this.list[key]) {
this.list[key] = [];
}
// 将回调函数推入该消息的缓存列表
this.list[key].push(fn);
},
// 取消订阅方法
unsubscribe: function(key, fn) {
// 如果有该消息的缓存列表
if (this.list[key]) {
// 遍历缓存列表
for (var i = this.list[key].length - 1; i >= 0; i--) {
// 如果存在该回调函数,就从缓存列表中删除
if (this.list[key][i] === fn) {
this.list[key].splice(i, 1);
}
}
}
},
// 发布方法
publish: function() {
// 获取消息类型
var key = Array.prototype.shift.call(arguments);
// 获取该消息的缓存列表
var fns = this.list[key];
// 如果没有订阅该消息,就返回
if (!fns || fns.length === 0) {
return;
}
// 遍历缓存列表,执行回调函数
for (var i = 0; i < fns.length; i++) {
fns[i].apply(this, arguments);
}
}
};
// 定义一个订阅者对象A
var subA = function(name) { console.log('A收到了消息:' + name); };
// 定义一个订阅者对象B
var subB = function(name) { console.log('B收到了消息:' + name); };
// A订阅了test消息
pub.subscribe('test', subA);
// B订阅了test消息
pub.subscribe('test', subB);
// 发布了test消息,传递了参数 'hello'
pub.publish('test', 'hello');
// 输出:
// A收到了消息:hello
// B收到了消息:hello
// A取消订阅了test消息
pub.unsubscribe('test', subA);
// 发布了test消息,传递了参数 'world'
pub.publish('test', 'world');
// 输出: // B收到了消息:world