概念
发布---订阅模式又叫观察者模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知
使用场景
当一个对象改变时同时改变其它对象,并且它不知道具体有多少对象需要改变的时候,就应该考虑使用观察者模式。
优点
- 支持简单的广播通信,当对象状态发生改变时,会自动通知已经订阅过的对象。
- 发布者与订阅者耦合性降低,职责单一,发布者只管负责发布消息,不用管订阅者如何实现,相对的订阅者只管负责处理自己的事情,不需要考虑发布者有哪些变化。
缺点
因为需要给发布者开辟一个内存去存储订阅者的信息,所以会有一定的内存开销。
实现订阅和发布模式
1.简洁版
var publishMessage = {};//定义对象用来进行数据的存储
//创建订阅者
function registEntiy(regist,callback){//regist:注册的事件名称,callback:回调函数
if(!publishMessage[regist]){
publishMessage[regist] = [];
}
publishMessage[regist].push(callback);
}
//创建发布者
function publishEntiy(regist,args){
if(!publishMessage[regist]){
return;
}
for(var i=0,lengths = publishMessage[regist].length;i<lengths;i++){
publishMessage[regist][i](args);//执行回调
}
}
//测试
//创建三个订阅者
registEntiy('step1',function(data){
console.log('this is '+data.index);
})
registEntiy('step2',function(data){
console.log('this is ' +data.index);
})
registEntiy('step3',function(data){
console.log('this is '+data.index);
})
//发布者进行信息的发布
publishEntiy('step1',{index:1});.//this is 1
publishEntiy('step2',{index:2});.//this is 2
publishEntiy('step3',{index:3});.//this is 3
//小结
//通过如上代码相信大家已经理解订阅和发布模式的原理,简单来说就是开辟一个内存来存储用来处理的即将执行的事情,我们将其称为订阅者,好似订餐时的消费者,先点菜,我不管你怎么做的,只要做好了你给我送过来就好。在某一特定时间后通过订阅者的注册时的key来执行相应的回调,此时的发布者就是餐馆的服务员,他通过点菜是的号码,在菜做好之后,然后将菜送到对应的用餐者那里
2.封装版
上面的代码看起来比较零散,现在我们将其进行封装,并完善
function ObserverModel(){
this.message = {};
}
//发布者
ObserverModel.prototype.publish = function(){
var key = Array.prototype.shift.call(arguments); //取出订阅者消息名称
var fns = this.message[key];//取出该消息名称下的回调函数
if(!this.message[key]){
return;
}
for(var i = 0 ,lengths =fns.length;i<lengths ;i++ ) {
fns[i].apply(this,arguments); // arguments 是发布消息时附送的参数
}
}
//注册者
ObserverModel.prototype.regist = function(key,fn){
if(!this.message[key]){
this.message[key] = [];
}
this.message[key].push(fn);
}
//增加一个注销者
ObserverModel.prototype.remove = function(key){
if(!this.message[key]){
return
}
for(var i in this.message){
if(this.message.hasOwnProperty(i)){
if(i === key){
this.message[i] = null;
return;
}
}
}
}
//测试
var observer = new ObserverModel();
observer.regist('start',function(data){console.log('this is start '+data)});//订阅
observer.publish('start',2);//发布
//结果
this is start 2
observer.regist('start',function(data){console.log('this is start '+data)});//订阅
observer.remove('start');//退订订阅者
observer.publish('start',2);//发布
//结果
没有回调函数执行,说明退订成功
3.运用项目中
在我们项目中经常会进行ajax请求然后执行相关的回调函数,现在让我们运用这种模式来进行优化,看如下代码
//场景 在初始化的时候,客户端需要通过服务端传回的数据进行渲染页面,如 拿到数据后要进行l两个模块的渲染如下
function renderPage1(data){
......
}
function renderPage2(data){
......
}
//常规方法
$.ajax('get',url,function(data){renderPage1(data);renderPage2(data)});
//此时每当我们需要增加一个渲染函数时,我们都有在ajax执行成功的回调函数进行增加一个指向函数,这样耦合性就会很高,不利于以后的维护
//采用观察者模式,使用我们刚刚封装的方法
var observer = new ObserverModel();
observer.regist('success',renderPage1);//注册
observer.regist('success',renderPage2);//注册
$.ajax('get',url,function(data){observer.publish('success',data));//发布
//这种写法耦合性就会很低
4总结
订阅和发布模式也称作观察者模式,其使用的场景在于一个对象的变化会导致多个对象的响应改变,原理是利用内存通过键值的方式进行先行存储即订阅,然后当这一个对象变化时进行去执行内存中存储的信息,根据键去查找相应的值然后执行相应的订阅者,优点是耦合性低,可以用作信息的广播。