Java教程

javascript设计模式实现之-发布-订阅模式(又称观察者模式)

本文主要是介绍javascript设计模式实现之-发布-订阅模式(又称观察者模式),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

       相对而言,设计模式概念在前端开发中其实没有那么受重视,很多小伙伴可能都做过好几年的前端开发也并没有用到设计模式相关知识,然后没有用到并不等于以后也不会用到,更不等于真的就不重要。

       还是先来看下设计模式(Design pattern)的定义:设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的(摘自 菜鸟教程 https://www.runoob.com/design-pattern/design-pattern-tutorial.html) 。既然是一般问题的解决方案,必然也会适用于前端,而实际上前端知识中最基础的dom事件机制就用到了 设计模式中的 发布订阅模式,Promise的实现也用到了发布订阅模式,最近几年国内流行的SPA(单页面应用)开发框架 vue同样用到了发布订阅模式。本文就尝试对 在前端开发中 应用相对较多的 发布-订阅模式作下解析。

        以下斜体部份摘自《javascript设计模式与开发实践》

       不论是在程序世界里还是现实生活中,发布-订阅模式的应用都非常之广泛。我们先看一个现实中的例子。小明最近看上了一套房子,到了售楼处之后才被告知,该楼盘的房子早已售罄。好在售楼MM 告诉小明,不久后还有一些尾盘推出,开发商正在办理相关手续,手续办好后便可以购买。但到底是什么时候,目前还没有人能够知道。于是小明记下了售楼处的电话,以后每天都会打电话过去询问是不是已经到了购买时间。除了小明,还有小红、小强、小龙也会每天向售楼处咨询这个问题。一个星期过后,售楼 MM 决定辞职,因为厌倦了每天回答 1000 个相同内容的电话。当然现实中没有这么笨的销售公司,实际上故事是这样的:小明离开之前,把电话号码留在了售楼处。售楼 MM 答应他,新楼盘一推出就马上发信息通知小明。小红、小强和小龙也是一样,他们的电话号码都被记在售楼处的花名册上,新楼盘推出的时候,售楼 MM 会翻开花名册,遍历上面的电话号码,依次发送一条短信来通知他们。

        在以上例子中,发送短信通知就是一个典型的发布-订阅模式,小明、小红等购买者都是订阅者,他们订阅了房子开售的消息。售楼处作为发布者,会在合适的时候遍历花名册上的电话号码,依次给购房者发布消息。

        可以发现,在这个例子中使用发布—订阅模式有着显而易见的优点。

  1. 购房者不用再天天给售楼处打电话咨询开售时间,在合适的时间点,售楼处作为发布者会通知这些消息订阅者。
  2. 购房者和售楼处之间不再强耦合在一起,当有新的购房者出现时,他只需把手机号码留在售楼处,售楼处不关心购房者的任何情况,不管购房者是男是女还是一只猴子。 而售楼处的任何变动也不会影响购买者,比如售楼 MM 离职,售楼处从一楼搬到二楼,这些改变都跟购房者无关,只要售楼处记得发短信这件事情。       

 

        第一点说明发布—订阅模式可以广泛应用于异步编程中,这是一种替代传递回调函数的方案。比如,我们可以订阅 ajax 请求的 error、 succ 等事件。 或者如果想在动画的每一帧完成之后做一些事情,那我们可以订阅一个事件,然后在动画的每一帧完成之后发布这个事件。在异步编程中使用发布—订阅模式,我们就无需过多关注对象在异步运行期间的内部状态,而只需要订阅感兴趣的事件发生点。

        第二点说明发布—订阅模式可以取代对象之间硬编码的通知机制,一个对象不用再显式地调用另外一个对象的某个接口。发布—订阅模式让两个对象松耦合地联系在一起,虽然不太清楚彼此的细节,但这不影响它们之间相互通信。当有新的订阅者出现时,发布者的代码不需要任何修改;同样发布者需要改变时,也不会影响到之前的订阅者。只要之前约定的事件名没有变化,就可以自由地改变它们。

 

         以下为 发布订阅模式 的 一种代码实现:

class PubSub {         constructor() {           this.handles = {};         }
        // 订阅         on(eventType, handle) {           if (!this.handles.hasOwnProperty(eventType)) {             this.handles[eventType] = [];           }           if (typeof handle == 'function') {             this.handles[eventType].push(handle);           } else {             throw new Error('No callback');           }           return this;         }
        // 发布         emit(eventType, ...args) {           if (this.handles.hasOwnProperty(eventType)) {             this.handles[eventType].forEach((item, key, arr) => {               item.apply(null, args);             });           } else {             throw new Error(`"${eventType}"事件未注册`);           }           return this;         }
        // 删除         off(eventType, handle) {           if (!this.handles.hasOwnProperty(eventType)) {             throw new Error(`"${eventType}"事件未注册`);           } else if (typeof handle != 'function') {             throw new Error('No callback');           } else {             this.handles[eventType].forEach((item, key, arr) => {               if (item == handle) {                 arr.splice(key, 1);               }             });           }           return this; // 实现链式操作         }       }
      // 以下为后续要订阅的一个动作       let callback = function () {         console.log('you are so nice');       };
      let pubsub = new PubSub();       // 订阅       pubsub         .on('completed', (...args) => {           console.log(args.join(' '));         })         .on('completed', callback);              // 发布
      pubsub.emit('completed', 'I love you', 'baby');       //   pubsub.off('completed', callback);       pubsub.emit('completed', 'I love you so much!');



输出如下:

I love you baby

you are so nice

I love you so much!

you are so nice

 

这篇关于javascript设计模式实现之-发布-订阅模式(又称观察者模式)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!