Tout d'abord, extraitons l'introduction du texte du livre Modèles de conception et pratiques de développement JavaScript//Publier et s'abonner au modèle en réalité
Xiao Ming est récemment tombé amoureux d'une maison et on lui a dit après son arrivée au bureau de vente, Les maisons de ce développement sont déjà vendues. Heureusement, le responsable des ventes a déclaré à Xiao Ming qu'il y aurait des lancements tardifs dans un avenir proche, que le développeur suivait les procédures pertinentes et que vous pourrez les acheter une fois les procédures terminées. Mais quand exactement cela aura lieu, personne ne peut encore le savoir. Alors Xiao Ming notait le numéro de téléphone du bureau de vente et l'appelait tous les jours pour lui demander s'il était temps d'acheter. En plus de Xiao Ming, Xiao Hong, Xiao Qiang et Xiao Long consultent également quotidiennement le bureau des ventes sur cette question. Au bout d'une semaine, le vendeur a décidé de démissionner car il en avait assez de répondre chaque jour à 1 000 appels avec le même contenu.
Bien sûr, il n'existe pas de société de vente aussi stupide en réalité. La véritable histoire est la suivante : Xiao Ming a laissé son numéro de téléphone au bureau de vente avant de partir. La vendeuse lui a promis qu'il enverrait un message pour informer Xiao Ming dès le lancement de la nouvelle propriété. Il en va de même pour Xiaohong, Xiaoqiang et Xiaolong. Leurs numéros de téléphone sont tous enregistrés sur la liste du bureau de vente. Lorsqu'une nouvelle propriété est lancée, la vendeuse ouvre la liste, parcourt les numéros de téléphone et envoie un SMS. message un par un pour les informer. Dans l'exemple ci-dessus, l'envoi de notifications par SMS est un modèle de publication-abonnement typique. Des acheteurs tels que Xiao Ming et Xiao Hong sont abonnés et se sont abonnés aux informations indiquant que la maison est à vendre. En tant qu'éditeur, le bureau des ventes examinera les numéros de téléphone figurant sur la liste au moment opportun et publiera à son tour les nouvelles aux acheteurs de maison.
On constate que l’utilisation du modèle de publication-abonnement dans cet exemple présente des avantages évidents. Les acheteurs de maison n'ont plus besoin d'appeler le bureau des ventes tous les jours pour se renseigner sur l'heure de la vente, le moment venu, le bureau des ventes, en tant qu'éditeur, informera les abonnés de ces messages. Il n'y a plus de lien fort entre les acheteurs de maison et le bureau de vente. Lorsqu'un nouvel acheteur de maison apparaît, il lui suffit de laisser son numéro de téléphone portable au bureau de vente. Le bureau de vente ne se soucie pas de la situation de l'acheteur de maison. quel que soit l’acheteur de la maison, s’il s’agit d’un homme, d’une femme ou d’un singe. Tout changement dans le bureau des ventes n'affectera pas les acheteurs. Par exemple, le MM des ventes a démissionné et le bureau des ventes a déménagé du premier étage au deuxième étage. Ces changements n'ont rien à voir avec les acheteurs, tant que le bureau des ventes. n'oublie pas d'envoyer des SMS.
Tout d'abord, précisez qui agira en tant qu'éditeur (comme le bureau des ventes) ; puis ajoutez une liste de cache à l'éditeur pour stocker les fonctions de rappel pour avertir les abonnés (liste du bureau des ventes) et enfin publier lors de l'envoi d'un ; message, l'éditeur parcourra cette liste de cache et déclenchera à son tour les fonctions de rappel d'abonné qui y sont stockées (parcourir la liste et envoyer des messages texte un par un). De plus, nous pouvons également renseigner certains paramètres dans la fonction de rappel, et les abonnés peuvent recevoir ces paramètres. Ceci est très nécessaire. Par exemple, le bureau des ventes peut ajouter le prix unitaire, la superficie, le ratio de surface au sol et d'autres informations de la maison aux SMS envoyés aux abonnés. Après avoir reçu ces informations, les abonnés peuvent effectuer leur propre traitement :
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>观察者模式</title> </head> <body> <button id="count">点我</button> <p id="show"></p> <script> //我的个人理解 //发布者首先需要一个对象来保存事件的回调函数,这个对象的属性就是事件类型,比如{"click":[fn1,fn2],"mouseover":[fn3,fn4]} //订阅事件:首先要判断这个事件类型是否存在当前的对象上,如果不存在那就初始化一下就是添加这个属性,并且给这个属性的值设置为空数组 //如果已经存在了那么久开始把该对调函数push进去对应的属性的值, 该值为一个数组 //发布事件:发布事件就要一个个的通知订阅者,还有就是你发布了什么事件。这里要有if判断, // 先从参数中取出要发布事件的key,然后获取到key对应的回调函数数组,取出数组后先判断数组是否存在或者数组长度是否为0,如果不存在或者为0 //就结束程序,若上述条件不成立就执行for循环,一次遍历回调函数数组,并执行里面的函数,这里需要改变回调函数的this指向。防止丢之 //this。 //移出事件:先判断要移出的key的值是否为空,若空则退出程序否则再判断是否传入了要移出哪个回调函数,若空,则认为要移出全部的函数,就把数组长度设置为0 // //下面是js设计模式与开发实践上的实现过程 var Event=(function(){ var clientList={}, listen, trigger, remove; listen=function(key,fn){ if(!clientList[key]){ clientList[key]=[]; } clientList[key].push(fn); }; trigger=function(){ var key=Array.prototype.shift.call(arguments), cb=clientList[key]; if(!cb||cb.length==0){ return false;//如果没有保存回调函数就退出程序 } for(var i=0;i<cb.length;i++ ){ cb[i].apply(this,arguments);//为什么要用applly呢,这是为了把触发时传入的参数传入给cb[i]对应的回调函数里面使用并且还要改变this指向 } }; remove=function (key,fn) { var cb=clientList[key]; if(!cb){ return false;//如果要移除的key的值为空就代表没有人订阅该key和设置回调函数则直接返回 } if(!fn){//如果没有传入具体的回调函数,表示需要取消key对应的消息的所有订阅 cb&&(cb.length=0);//这里cb是已经存在了就把cb的length设置为0.我有疑问,到这里其实cb不会不存在了吧上面如果不存在就退出了如何会走到这一步? } else{ for(var l=0;l<cb.length;l++){ var _cb=cb[l]; if(_cb===fn){//寻找哪个和要删除的回调函数一样 cb.splice(l,1);//从l处删除一个元素 } } } }; return { listen:listen, trigger:trigger, remove:remove }//这里返回这个对象其实是相当于中介代理的意思,请看下面的实际例子解释: //我们给每个发布者对象都添加了listen 和trigger 方法,以及一个缓存列表clientList, //这其实是一种资源浪费。 //小明跟售楼处对象还是存在一定的耦合性,小明至少要知道售楼处对象的名字是 //才能顺利的订阅到事件。 //因此返回一个通用的对象,不必知道这个对象的名字,只需要把这个对象的一个引用给一个变量就行了 })(); Event.listen("A",fn1=function(data){ console.log(data); }) Event.listen("A",fn2=function(data){ console.log(data); }) Event.remove("A",fn1); Event.trigger("A","猴赛雷啊"); </script> <script> var a=(function(){ var count=0; var btn=document.getElementById('count'); btn.onclick=function () { Event.trigger('add',count++); } })(); var b=(function () { var p=document.getElementById('show'); Event.listen('add',function(data){ p.innerHTML=data; }) })(); </script> </body> </html>
Enfin, l'auteur a également expliqué les inconvénients du modèle de publication-abonnement :
Si trop de modèles globaux de publication-abonnement sont utilisés entre les modules, Communication, puis la connexion entre les modules est cachée dans les coulisses. Nous ne pourrons finalement pas déterminer de quel module provient le message, ni vers quels modules le message sera envoyé, ce qui posera quelques problèmes à notre maintenance. Peut-être que le rôle d'un certain module est d'exposer certaines interfaces<.> pour d'autres modules à appeler .