观察者模式定义了对象间的一种一对多的依赖关系。而发布订阅模式是观察者模式的衍生模式,它进一步解耦了发布者与观察者的依赖关系,并且能够更细粒度的控制依赖关系。
观察者模式(Observer)
定义
观察者模式(Observer Pattern):定义了对象间一种一对多的依赖关系,当目标对象 Subject 的状态发生改变时,所有依赖它的对象 Observer 都会得到通知。
模式结构
- Subject:目标者对象。
- Observer:观察者对象。
Subject与Observer需要一一对应的逻辑耦合方法。由Subject管理订阅、取消订阅方法。
前端代码实现
// 目标者类
class Subject {
constructor() {}
addListener(eventName, observer) {
if (this[eventName]) {
this[eventName].events.push(observer);
} else {
this[eventName] = {
events: [observer]
};
}
return this;
}
removeListener(eventName, observer) {
const index = this[eventName].events.findIndex(item => item === observer);
index > -1 && this[eventName].events.splice(index, 1);
return this;
}
publish(eventName) {
if (this[eventName]) {
this[eventName].events.forEach(observer => {
observer.update && observer.update();
});
}
}
}
// 观察者类
class Observer {
constructor(id, name) {
this.name = name;
this.id = id;
}
// 目标对象更新时触发的回调
update() {
console.log(`目标者通知我更新了,我是:${this.name}`);
}
}
// 实例化目标者
let subject = new Subject();
// 实例化两个观察者
let obs1 = new Observer("a", "小明");
let obs2 = new Observer("b", "小红");
let obs3 = new Observer("c", "小懒");
// 向目标者添加观察者
subject.addListener("listen", obs1);
subject.addListener("listen", obs2);
subject.addListener("listen2", obs3);
// 目标者通知更新
subject.publish("listen");
subject.publish("listen2");
发布订阅模式(Publisher && Subscriber)
定义
发布订阅模式:基于一个事件(主题)通道,希望接收通知的对象 Subscriber 通过自定义事件订阅主题,被激活事件的对象 Publisher 通过发布主题事件的方式通知各个订阅该主题的 Subscriber 对象。
模式结构
- Subject:目标者对象。
- Observer:观察者对象。
- Broker:事件中心。
Subject与Observer完全解耦。由Observer管理订阅、取消订阅方法。
前端代码实现
为了便于大家理解,下面代码中创建了Observer观察者类。如果是前端具体的DOM更新场景下,可查看“DOM场景示例”——发布订阅模式
// 目标者类
class Subject {
constructor() {}
addListener(eventName, callback) {
if (this[eventName]) {
this[eventName].events.push(function() {
return callback.call(this, eventName);
});
} else {
this[eventName] = {
events: [
function() {
return callback.call(this, eventName);
}
]
};
}
return this;
}
removeListener(eventName) {
delete this[eventName];
return this;
}
publish(eventName, eventIndex) {
if (this[eventName]) {
this[eventName].events.forEach(callback => {
callback && callback();
});
}
}
}
// 观察者类
class Observer {
constructor(name) {
this.name = name;
}
// 目标对象更新时触发的回调
update() {
console.log(`目标者通知我更新了,我是:${this.name}`);
}
}
// 实例化目标者
const subject = new Subject();
// 实例化两个观察者
let obs1 = new Observer('前端开发者');
let obs2 = new Observer('后端开发者');
// 事件中心
subject.addListener("gotoclass", function(eventName) {
obs1.update();
});
subject.addListener("gotoclass", function(eventName) {
obs2.update();
});
// 目标者通知更新
subject.publish("gotoclass");
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。