发布订阅模式又叫观察者模式,它定义了对象间一对多的依赖关系,一个对象的状态发生改变时,所有依赖他的对象都会得到通知。JS里可以用事件模型来替代发布订阅模式。 (引用自JS设计模式与开发实践)
本文会由浅入深的实现一个订阅发布者模式一个最简单的订阅发布者模式
一个发布者对象(observer),包括了一个缓存数组(cacheList), 一个订阅方法(listen), 和一个发布方法(trigger),
var observer = {};
observer.cacheList = [];
observer.listen = function(fn) {
observer.cacheList.push(fn)
}
observer.trigger = function() {
for(var i = 0; i < observer.cacheList.length; i++) {
observer.cacheList[i].apply(this, arguments)
}
}
observer.listen(function oneListen(arg) {
console.log(`第一个订阅者收到:${arg}`)
})
observer.listen(function twoLis(arg) {
console.log(`第二个订阅者收到:${arg}`)
})
observer.trigger('推送消息')
我们可以在控制台看到打印
完整实现
上面实现的是一个只支持对订阅者群发的实现, 完善他的功能
- 为每个订阅者添加一个标识(name),可以根据标识筛选出对应的订阅者
- 添加一个退订方法(remote)
var observer: any = {};
observer.cacheList = {};
observer.listen = function (key: string, fn: any) {
if (!observer.cacheList[key]) {
observer.cacheList[key] = [];
}
observer.cacheList[key].push(fn);
};
observer.trigger = function (name: string, data: any) {
if (observer.cacheList[name]) {
observer.cacheList[name].forEach((e: any) => e(data));
}
};
observer.remote = function (name: string, Fn: any) {
if (!observer.cacheList[name]) return;
const index = observer.cacheList[name].indexOf(Fn);
if (!~index) return;
observer.cacheList[name].splice(index, 1);
};
function oneListen(arg: any) {
console.log(`第一个订阅者收到:${arg}`);
}
observer.listen("oneListener", oneListen);
function twoLis(arg: any) {
console.log(`第二个订阅者收到:${arg}`);
}
// 测试数据
observer.listen("twoLiser", twoLis);
observer.trigger("oneListener", "推送消息");
observer.trigger("twoLiser", "推送消息");
observer.remote("oneListener", twoLis);
observer.trigger("oneListener", "推送消息");
observer.remote("oneListener", oneListen);
observer.trigger("oneListener", "推送消息");
Class实现
class Observer {
cacheList: {};
constructor() {
this.cacheList = {};
}
listen(name, fn) {
if (typeof name !== "string") {
throw new Error(" name must be a string");
}
if (typeof fn !== "function") {
throw new Error("fn must be a function");
}
if (!this.cacheList[name]) {
this.cacheList[name] = [];
}
this.cacheList[name].push(fn);
}
remote(name, fn) {
if (typeof name !== "string") {
throw new Error(" name must be a string");
}
if (typeof fn !== "function") {
throw new Error("fn must be a function");
}
if (!this.cacheList[name]) return;
const index = this.cacheList[name].indexOf(Fn);
if (!~index) return;
this.cacheList[name].splice(index, 1);
}
trigger(name, data) {
if (typeof name !== "string") {
throw new Error("name name must be a string");
}
if (!this.cacheList[name]) return;
this.cacheList[name].forEach((callback) => callback(data));
}
}