1. 前言

发布订阅者模式是为了发布者和订阅者之间避免产生依赖关系,发布订阅者之间的订阅关系由一个中介列表来维护。发布者只需做好发布功能,至于订阅者是谁,订阅者做了什么事情,发布者是无需关心的

2. 什么是发布订阅模式

发布订阅:是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在。同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者(如果有的话)存在。(节选自百度百科)

就拿公众号来说

  1. 只有该公众号的订阅者才能收到推送
  2. 公众号只负责推送信息,不关心是谁订阅了我,只要有信息推送,那么就推送给所有的订阅者
  3. 订阅者无需时不时的查看公众号是否有信息推送,只要公众号推送信息后,该订阅者就会收到通知
  4. 订阅者可随时取消对该公众号的订阅

在调用方法时首先要发布方法,确保调用方法能够正常调用到。可以向一类相同事件中添加很多方法。当调用这一类方法时,可以统一调用整个流程。

发布订阅者模式,可以让我们不再涉及更多的回调处理,而且可以使模块的颗粒度更小。比如有个ajax的数据展示,其中一个订阅者A可以只负责数据的表格展示,另一个订阅者B只负责数据总量的计算。当有需求要把数据总量的计算修改为当前页的数据总量和整体的数据总量计算,那么订阅者A是不用任何变动的!

3. 发布订阅优缺点

发布订阅模式确实为我们的代码带来最小的耦合,并不是所有场景都适合使用这种模式,这种模式也有其利弊。

优点

  1. 支持简单的广播通信,自动通知所有已经订阅过的对象。
  2. 页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性。
  3. 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。

缺点

模块之间如果用了太多的全局发布-订阅模式来通信,那么模块与模块之间的联系就被隐藏到了背后,我们最终会搞不清楚消息来自哪个模块,或者消息会流向哪些模块,这又会给我们的维护带来一些麻烦,也许某个模块的作用就是暴露一些接口给其他模块调用。

4. 举例

上面说了那么多都是纸上谈兵,那么到底该订阅发布模式该如何实现呢?

简单实现

class Boos {
  constructor(){
    this.peopleList = {};
  }
  add(key,fn){
    let {peopleList} = this;
    !peopleList[key] && (peopleList[key] = []);
    this.peopleList[key].push(fn);
  }
  run(...arg){
    let key = Array.prototype.shift.call(arg);
    let {peopleList} = this;
    let fns = peopleList[key];
    if(!fns && !fns.length) return false;
    fns.forEach((el) => {
      el.apply(this,arg);
    })
  }
  remove(key,fn){
    let {peopleList} = this;
    let fns = peopleList[key];
    if(!fns && !fns.length) return false;
    fns.forEach((el,index) => {
      if(el===fn) {
        fns.splice(index,1);
      }
    })
  }
}
let boos = new Boos();
let married = (name) => {
  console.log(`${name}上班`);
}
let unemployment = (name) => {
  console.log(`${name}出差`);
}
boos.add('marrgie',married)
boos.add('unemployment',unemployment)
boos.run('marrgie','张三');
boos.remove('unemployment',unemployment);
boos.run('unemployment','李四');
boos.run('marrgie','李四');

上面Boos类,可以拥有发布,执行和删除任务,boos给某个员工发布命令,让员工做他应该做的事情。无论是上班还是出差,我们不需要关系他们具体如何实现,只需要boos知道员工能做什么事情就好了。

优化

class Boos {
  constructor(){
    this.peopleList = {};
  }
  add(key,fn){
    let {peopleList} = this;
    !peopleList[key] && (peopleList[key] = []);
    this.peopleList[key].push(fn);
  }
  run(...arg){
    let key = Array.prototype.shift.call(arg);
    let {peopleList} = this;
    let fns = peopleList[key];
    console.log(key)
    if(!fns && !fns.length) return false;
    fns.forEach((el) => {
      el.apply(this,arg);
    })
  }
  remove(key,fn){
    let {peopleList} = this;
    let fns = peopleList[key];
    if(!fns && !fns.length) return false;
    fns.forEach((el,index) => {
      if(el===fn) {
        fns.splice(index,1);
      }
    })
  }
}
class Work {
  married(name){
    console.log(`${name}上班`);
  }
  unemployment(name){
    console.log(`${name}出差`);
  }
  writing(name){
    console.log(`${name}写作`);
  }
  writeCode(name){
    console.log(`${name}打代码`);
  }
}
class Staff {
  constructor(name){
    this.name = name;
  }
  getName(){
    return this.name;
  }
}
let boos = new Boos();
let work = new Work();
let aaron = new Staff("Aaron");
let angie = new Staff("Angie");
let aaronName = aaron.getName();
let angieName = angie.getName()
boos.add(aaronName,work.married);
boos.add(aaronName,work.writing);
boos.add(aaronName,work.writeCode);
boos.add(angieName,work.unemployment);
boos.run(aaronName,aaronName);
boos.run(angieName,angieName);

上面共维护了三个类,每个类都在做自己的事情,boos可以为员工分配不同的工作,即时需要添加工作类与类之间没有任何沟耦合性。各自维护自己,任意一个类发生变化都不会互相影响。

总结

上面简单的实现了一下发布订阅者模式的模型,在样例代码中,我们也能够看到,发布者和订阅者之间仅仅依靠订阅关系来维持,而且发布者也不用关心订阅者的内部具体是怎么实现的。

设计模式-发布订阅模式(javaScript)的更多相关文章

  1. javascript设计模式——发布订阅模式

    前面的话 发布—订阅模式又叫观察者模式,它定义对象间的一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知.在javascript开发中,一般用事件模型来替代传统的发布—订阅模 ...

  2. js设计模式--发布订阅模式

    前言 本系列文章主要根据<JavaScript设计模式与开发实践>整理而来,其中会加入了一些自己的思考.希望对大家有所帮助. 概念 发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的 ...

  3. [转]js设计模式—发布订阅模式

    发布—订阅模式又叫观察者模式,它定义对象间的一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知.在javascript开发中,一般用事件模型来替代传统的发布—订阅模式.本文将 ...

  4. js设计模式-发布/订阅模式

    一.前言 发布订阅模式,基于一个主题/事件通道,希望接收通知的对象(称为subscriber)通过自定义事件订阅主题,被激活事件的对象(称为publisher)通过发布主题事件的方式被通知. 就和用户 ...

  5. javascript 设计模式 -- 发布/订阅模式

    直接上代码: index.html : <!DOCTYPE html> <html lang="en"> <head> <meta cha ...

  6. 理解JavaScript设计模式与开发应用中发布-订阅模式的最终版代码

    最近拜读了曾探所著的<JavaScript设计模式与开发应用>一书,在读到发布-订阅模式一章时,作者不仅给出了基本模式的通用版本的发布-订阅模式的代码,最后还做出了扩展,给该模式增加了离线 ...

  7. [转] JavaScript设计模式之发布-订阅模式(观察者模式)-Part1

    <JavaScript设计模式与开发实践>读书笔记. 发布-订阅模式又叫观察者模式,它定义了对象之间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖它的对象都将得到通知. 例如 ...

  8. 《JavaScript设计模式与开发实践》-- 发布-订阅模式

    详情个人博客:https://shengchangwei.github.io/js-shejimoshi-fabudingyue/ 发布-订阅模式 1.定义 发布-订阅模式:发布-订阅模式又叫观察者模 ...

  9. JavaScript设计模式(发布订阅模式)

    发布—订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知.在JavaScript开发中,我们一般用事件模型来替代传统的发布—订阅模式 ...

随机推荐

  1. Python_pickle模块操作二进制文件

    import pickle b=7 i=13000000 fa=99.056 s='中国人民 123abc' lst=[[1,2,3],[4,5,6],[7,8,9]] tu=(-5,10,8) co ...

  2. Maven学习(六)-- Maven与Eclipse整合

    由于我使用的是IDEA所以就不摘录了,感兴趣的移步 Maven学习总结(六)--Maven与Eclipse整合 Maven学习总结(七)--eclipse中使用Maven创建Web项目  

  3. Oracle-02:SQL语言的分类或者说SQL语言的组成

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 小结一版:  01.DDL(Data Definition Language)数据定义语言. 用来创建数据库中 ...

  4. CORS 实战 专题

    本文会代码层面对CORS问题进行剖析 CORS相关相关概念可参考http://www.cnblogs.com/softidea/p/5496719.html ERROR info: XMLHttpRe ...

  5. 使用Map标签指定点击区域时的兼容性问题

    电商m站的首页,有一个需求是配一张大的banner图,然后指定某些区域是热区,点击之后跳转到不同的活动页. 听起来简单明了,实现也比较容易,立刻就想起来有个map标签,简直就是为这个需求量身定做. 简 ...

  6. charles模拟手机流量网速

    找到proxy--throttle settings 勾选enable throttling,设置手机上网网速 选择throttle preset,有设置好的一些网速,可以随便选 也可以设置2G网络, ...

  7. PHP与XML技术

    XML的概述 XML(eXtensibleMarkup Language),扩展性标记语言,它是用来描述其他语言的语言.它允许用户设计自己的标记.XML是由W3C(WorldWide 月发布的一种标准 ...

  8. 基于 HTML5 OpenLayers3 实现 GIS 电信资源管理系统

    前言 通过结合 HTML5 和 OpenLayers 可以组合成非常棒的一个电信地图网络拓扑图的应用,形成的效果可以用来作为电信资源管理系统,美食定位分享软件,片区找房,绘制铁轨线路等等,各个领域都能 ...

  9. consoleWriter.go

    package blog4go import ( "fmt" "os" "time" ) // ConsoleWriter is a con ...

  10. Hadoop问题:DataNode进程不见了

      DataNode进程不见了 问题描述 最近配置Hadoop的时候出现了这么一个现象,启动之后,使用jps命令之后是这样的: 看不到DataNode进程,但是能够正常的工作,是不是很神奇啊? 在一番 ...