JavaScript设计模式-观察者模式
bojue opened this issue · 0 comments
bojue commented
JavaScript设计模式-观察者模式
观察者模式又称为发布-订阅者模式,用来处理消息对象和消息观察者之间的耦合关系。
观察者模式的消息对象,一般包括三个主要的方法,分别是消息发布,消息订阅和取消订阅。为了防止消息队列被篡改,需要用到闭包创建私有变量存储消息队列容器。
let Observer = (() => {
var _message = {};
return {
subscribe:() => {}, //订阅
emit: () => {}, //发布
remove:() => {} //移除订阅
}
})()
这段代码摘录自《JavaScript设计模式》,涵盖了观察者模式对象的基本骨架,我们需要页面加载完成的时候创建出观察者对象,所以使用了立即执行函数。
下面我们需要依次实现订阅者模式的主体方法。
消息订阅
订阅者模式,首先需要保证消息对象是可以被订阅的,同时满足多个不同模块订阅同一个消息,我们使用type字段区分不同的订阅模块,使用数组存储消息的订阅队列。
subscribe: (type, fun) => {
if(typeof _message[type] === 'undefined') {
_message[type] = []
}
_message[type].push(fun)
}
发布消息
观察者模式消息的发布,首先需要验证消息类型是否已经被注册过,注册过的消息类型直接添加消息类型对应的消息队列,否则需要先创建该消息类型对应的消息队列,然后添加消息。
emit: (type, param) => {
if(!_message[type]) {
return false;
}
let obj = {
type: type,
args: param
}
let len = _message[type].length;
for(let i=0; i<len; i++) {
_message[type][i].call(this, obj);
}
}
取消订阅
与消息发布类似,取消订阅操作需要首先对消息队列的消息列表进行验证,确保该类型的消息队列的存在性,否则没有意义。
remove: (type, fun) => {
if(!Array.isArray(_message[type])) {
return false;
}
let len = _message[type].length - 1;
for(i = len; i>= 0;i--) {
let arr = _message[type];
if(arr == fun) {
arr.splice(i, 1)
}
}
}
测试
/**
* 控制台打印的内容:
* 订阅的消息类型:node, 消息内容:node 设计模式
* >>>>>>> 订阅操作Error:没有注册js类型的事件 !!!
* >>>>>>> 取消订阅操作Error:没有注册js类型的事件 !!!
*/
let Observer = (() => {
var _message = {};
return {
subscribe: (type, fun) => {
if(typeof _message[type] === 'undefined') {
_message[type] = []
}
_message[type].push(fun)
},
emit: (type, param) => {
if(!_message[type]) {
console.error(`>>>>>>> 订阅操作Error:没有注册${type}类型的事件 !!!`);
return false;
}
let obj = {
type: type,
args: param
}
let len = _message[type].length;
for(let i=0; i<len; i++) {
_message[type][i].call(this, obj);
}
},
remove: (type, fun) => {
if(!Array.isArray(_message[type])) {
console.error(`>>>>>>> 取消订阅操作Error:没有注册${type}类型的事件 !!!`);
return false;
}
let len = _message[type].length - 1;
for(i = len; i>= 0;i--) {
let arr = _message[type];
if(arr[i] === fun) {
_message[type].splice(i, 1)
}
}
}
}
})()
Observer.subscribe('node', val => {
let data = `订阅的消息类型:${val['type']}, 消息内容:${val['args']['msg']}`;
console.log(data)
})
Observer.emit('node', {
msg: 'node 设计模式'
})
Observer.emit('js', {
msg: 'javaScript 设计模式'
})
Observer.remove('js', val => {
let data = `订阅的消息类型:${val['type']}, 消息内容:${val['args']['msg']}`;
console.log(data)
})
因为我们订阅了node类型的事件,所以当发布node事件的时候我么可以观察到该事件,我们订阅队列不包含js事件类型所以观察不到js事件。
订阅者模式可以理解为观察对象的一个函数回调,但是又不完全一样。因为事件观察者模式处理的是观察者和被观察对象一对多的关系,函数回调是观察者模式的一种具体实现,但是函数回调处理的是一对一的关系。