Введение
Режим публикации-подписки также называется режимом наблюдателя, который определяет зависимость между объектами «один ко многим».При изменении состояния объекта все объекты, которые от него зависят, будут уведомлены. При разработке JavaScript мы обычно используем модель событий, чтобы заменить традиционную модель публикации-подписки.
Введение в дело 1
В последнее время Сяо Мин любит есть старое пекинское печенье, но когда он пришел в место, где продавали печенье, то обнаружил, что оно все распродано, а в очереди еще много людей.К счастью, ММ, который продавал печенье, увидел, что Сяо Мин был красивый, и сказал Сяо Мину, что через какое-то время у него будет печенье. Но у Сяо Мина все еще есть свидание. Я не знаю, когда кунжутный пирог будет готов. Ты не можешь перестать ходить на свидание. Только потому, что ты ешь кунжутный пирог!В это время у Сяо Мина возникла идея, и он сказал, что кунжутный пирог ММ позвонит мне!Я сначала буду занят, я позвоню, чтобы спросить тебя, готово ли печенье. Шаобин ММ не стал долго думать и дал Сяо Мину телефон. Позже Сяолун также пришел купить семена кунжута.Ситуация была похожа на Сяомин.Сяолун также оставил номер телефона семян кунжута ММ. Но вот в чем проблема: Сяомин и Сяолун позвонили ММ с семенами кунжута, из-за чего ММ с семенами кунжута очень раздражал и уволился с работы.
Благодаря вышеперечисленным вещам мы можем обнаружить, что есть много проблем
Во-первых: ММ, продающий печенье, должен выступать в роли издателя.
Во-вторых: номер телефона Сяомин Сяолун должен быть сохранен в списке пользователей, продающих печенье.Если MM, продающий печенье, уйдет, пользователь будет потерян.
Третье: на самом деле нет такого глупого способа продажи
Владелец магазина, который продает печенье, может записывать телефонные звонки Сяомин и Сяолун, а когда в магазине появится печенье, он уведомит Сяолуна и Сяомина, чтобы они пришли и купили их.Это так называемая модель публикации-подписки. составляет:
/*烧饼店*/
var Sesamecakeshop={
clienlist:[],//缓存列表
addlisten:function(fn){//增加订阅者
this.clienlist.push(fn);
},
trigger:function(){//发布消息
for(var i=0,fn;fn=this.clienlist[i++];){
fn.apply(this,arguments);
}
}
}
/*小明发布订阅*/
Sesamecakeshop.addlisten(function(price,taste){
console.log("小明发布的"+price+"元,"+taste+"味道的");
});
/*小龙发布订阅*/
Sesamecakeshop.addlisten(function(price,taste){
console.log("小龙发布的"+price+"元,"+taste+"味道的");
});
Sesamecakeshop.trigger(10,"椒盐");
Из кода видно, что только Сяомин и Сяолун заказали печенье, и магазин печенья может опубликовать сообщение, чтобы сообщить Сяолун и Сяолун. Но есть проблема, я не знаю, нашли ли вы ее. Сяо Мин любит только вкус перца и соли. А Сяолун любит только карамельный вкус. Приведенный выше код не удовлетворит потребности заказчика, он дает ему ощущение, что, нравится мне это или нет, вы мне его пришлете. Если публикаций будет слишком много, клиенту станет скучно, и он может даже захотеть удалить подписку. Следующее, чтобы улучшить код, вы можете взглянуть.
/*烧饼店*/
var Sesamecakeshop={
clienlist:{},/*缓存列表*/
/**
* 增加订阅者
* @key {String} 类型
* @fn {Function} 回掉函数
* */
addlisten:function(key,fn){
if(!this.clienlist[key]){
this.clienlist[key]=[];
}
this.clienlist[key].push(fn);
},
/**
* 发布消息
* */
trigger:function(){
var key=[].shift.call(arguments),//取出消息类型
fns=this.clienlist[key];//取出该类型的对应的消息集合
if(!fns || fns.length===0){
return false;
}
for(var i=0,fn;fn=fns[i++];){
fn.apply(this,arguments);
}
},
/**
* 删除订阅
* @key {String} 类型
* @fn {Function} 回掉函数
* */
remove:function(key,fn){
var fns=this.clienlist[key];//取出该类型的对应的消息集合
if(!fns){//如果对应的key没有订阅直接返回
return false;
}
if(!fn){//如果没有传入具体的回掉,则表示需要取消所有订阅
fns && (fns.length=0);
}else{
for(var l=fns.length-1;l>=0;l--){//遍历回掉函数列表
if(fn===fns[l]){
fns.splice(l,1);//删除订阅者的回掉
}
}
}
}
}
/*小明发布订阅*/
Sesamecakeshop.addlisten("焦糖",fn1=function(price,taste){
console.log("小明发布的"+price+"元,"+taste+"味道的");
});
/*小龙发布订阅*/
Sesamecakeshop.addlisten("椒盐",function(price,taste){
console.log("小龙发布的"+price+"元,"+taste+"味道的");
});
Sesamecakeshop.trigger("椒盐",10,"椒盐");
Sesamecakeshop.remove("焦糖",fn1);//注意这里是按照地址引用的。如果传入匿名函数则删除不了
Sesamecakeshop.trigger("焦糖",40,"焦糖");
При удалении следует учитывать, что если при подписке передается анонимная функция, если она передается при удалении, то это тоже анонимная функция. не может быть удален. Потому что удаление удаляется по ссылке на адрес. Две переданные анонимные функции имеют разные ссылки на адреса.
Введение в дело 2
Например, у наших общих удостоверений пользователей разные функции.Суперадминистратор имеет высшие полномочия и может удалять и изменять любого пользователя. Обычные пользователи могут изменять только данные своей учетной записи. Во-первых, это аутентификация пользователя.После прохождения проверки может отображаться соответствующая функция.
//登录发布-订阅模式
login={
clienlist:{},/*缓存列表*/
/**
* 增加订阅者
* @key {String} 类型
* @fn {Function} 回掉函数
* */
addlisten:function(key,fn){
if(!this.clienlist[key]){
this.clienlist[key]=[];
}
this.clienlist[key].push(fn);
},
/**
* 发布消息
* */
trigger:function(){
var key=[].shift.call(arguments),//取出消息类型
fns=this.clienlist[key];//取出该类型的对应的消息集合
if(!fns || fns.length===0){
return false;
}
for(var i=0,fn;fn=fns[i++];){
fn.apply(this,arguments);
}
}
}
//超级管理员修改所有用户
var editall=(function(){
login.addlisten("loginsucc",function(data){
editall.setview(data);
});
return{
setview:function(data){
console.log(data);
console.log("超级管理员修改所有用户");
}
}
})();
//仅仅修改自己
var editOwn=(function(){
login.addlisten("loginsucc",function(data){
editOwn.setview(data);
});
return{
setview:function(data){
console.log(data);
console.log("仅仅修改自己");
}
}
})();
Простая инкапсуляция модели публикации-подписки
var _Event=(function(){
var clienlist={},
addlisten,trigger,remove;
/**
* 增加订阅者
* @key {String} 类型
* @fn {Function} 回掉函数
* */
addlisten=function(key,fn){
if(!clienlist[key]){
clienlist[key]=[];
}
clienlist[key].push(fn);
};
/**
* 发布消息
* */
trigger=function(){
var key=[].shift.call(arguments),//取出消息类型
fns=clienlist[key];//取出该类型的对应的消息集合
if(!fns || fns.length===0){
return false;
}
for(var i=0,fn;fn=fns[i++];){
fn.apply(this,arguments);
}
};
/**
* 删除订阅
* @key {String} 类型
* @fn {Function} 回掉函数
* */
remove=function(key,fn){
var fns=clienlist[key];//取出该类型的对应的消息集合
if(!fns){//如果对应的key没有订阅直接返回
return false;
}
if(!fn){//如果没有传入具体的回掉,则表示需要取消所有订阅
fns && (fns.length=0);
}else{
for(var l=fns.length-1;l>=0;l--){//遍历回掉函数列表
if(fn===fns[l]){
fns.splice(l,1);//删除订阅者的回掉
}
}
}
};
return{
addlisten:addlisten,
trigger:trigger,
remove:remove
}
})();
_Event.addlisten("jianbing",function(d,all){
console.log("发布的消息来自:"+d+",具体信息:"+all);
});
_Event.addlisten("jianbing",function(d,all){
console.log("发布的消息来自:"+d+",具体信息:"+all);
})
_Event.trigger("jianbing","小小坤","前端工程师,擅长JavaScript,喜欢结交更多的前端技术人员,欢迎喜欢技术的你加QQ群:198303871")
Суммировать
Шаблон публикации-подписки часто называют шаблоном наблюдателя, который очень полезен при реальной разработке. Его преимущество в том, что он разъединяет по времени и деконструирует между объектами, Он широко используется и может помочь нам добиться более слабой развязки как в асинхронном программировании. Модель публикации-подписки также может помочь нам реализовать шаблоны проектирования.С архитектурной точки зрения и MVC, и MVVC незаменимы для участия в модели публикации-подписки. Однако у модели публикации-подписки есть и недостатки: само создание подписки занимает определенное количество времени и памяти, может после того, как вы подписались на сообщение, этого может и не произойти. Хотя модель «публикация-подписка» ослабляет связь между объектами, если ею злоупотреблять, необходимая связь между объектами и объектами будет глубоко запрятана, что затруднит отслеживание и поддержку программы.