一、基础介绍
观察者模式,定义对象间的一种一对多的依赖关系,解决主体对象与观察者之间功能的耦合。
在 JavaScript 中通常使用发布-订阅模式。
UML 类图二、代码实现观察者模式
class Subject {
constructor() {
this.observers = [];
}
// 订阅
listen(observer) {
this.observers.push(observer);
}
// 发布
trigger() {
this.observers.forEach(observer => {
observer.update();
})
}
// 移除
remove(observer) {
for(let i = this.observers.length - 1; i >= 0; i--) {
if (this.observers[i] === observer) {
this.observers.splice(i, 1);
}
}
}
}
class Observer {
constructor(name, subject) {
this.name = name;
this.subject = subject;
// 订阅
this.subject.listen(this);
}
update() {
console.log(`${this.name} 监听到了消息`);
}
}
测试代码运行结果
三、代码实现发布-订阅模式
const Event = (function () {
const eventList = {};
// 订阅
const listen = function(type, fn) {
if (!eventList[type]) {
eventList[type] = [];
}
eventList[type].push(fn);
}
const trigger = function() {
let type = [].shift.call(arguments);
let fns = eventList[type];
if (!fns || fns.length === 0) {
return false;
}
for (let i = 0; i < fns.length; i++) {
fns[i].apply(this, arguments);
}
}
const remove = function (type, fn) {
if (!fn) {
fns && (fns.length = 0);
} else {
for(let i = fns.length - 1; i >= 0; i--) {
if (fns[i] === fn) {
fns.splice(i, 1);
}
}
}
}
return {
listen,
trigger,
remove
}
})();
测试代码运行结果
三、观察者模式和发布-订阅模式的关系
相同点:
都解决了异步的问题。
不同点:
- 观察者模式中:
观察者(observer) 和 主体对象(subject) 具有强耦合。 - 发布-订阅模式中:
观察者和主体对象之间多了一个消息调度中心。
推荐阅读:
JavaScript Design Patterns
一像素:订阅发布模式和观察者模式真的不一样
MARKSZのBlog:观察者模式VS订阅发布模式
四、拓展
- 创建命名空间,避免事件类型冲突
- 实现类似 jquery 的
one()
, 即订阅的事件仅执行一次 - 缓存离线事件
参考
《JavaScript 设计模式与开发实践》曾探
《JavaScript 设计模式》张容铭
Javascript设计模式系统讲解与应用
网友评论