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. Java基础:内存模型

    1. 引言 2. Java内存模型 3. 内存间的交互操作 1. 引言 考虑到计算机组成的内容: 原始的计算机是CPU用于计算+硬盘用于存储,由于CPU的高速发展和硬盘的缓慢发展,高速的存储需要持续供 ...

  2. Python之命名空间、闭包、装饰器

    一.命名空间 1. 命名空间 命名空间是一个字典,key是变量名(包括函数.模块.变量等),value是变量的值. 2. 命名空间的种类和查找顺序 - 局部命名空间:当前函数 - 全局命名空间:当前模 ...

  3. jsoncpp linux平台编译和arm移植

    下载 http://sourceforge.net/projects/jsoncpp/ 或者 http://download.csdn.net/detail/chinaeran/8631141 Lin ...

  4. Robot framework(RF) Builti,Screenshot和Collections标准库介绍

    1.1  Builti标准类库 在学习一门编程语言的时候,大多教材都是从打印“hello world”开始.我们可以像编程语言一样来学习Robot Framework.虽然通过RIDE 提供“填表”一 ...

  5. 一个完整的html 每个标签的含义

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. VS2010+OpenMP的简单使用

    OpenMP是把程序中的循环操作分给电脑的各个CPU处理器并行进行.比如说我要循环运行100次,我的电脑有两个处理器,那OpenMP就会平均分给两个处理器并行运行,每个处理器运行50次.使用方法 1. ...

  7. vue项目如何刷新当前页面

    1.场景 在处理列表时,常常有删除一条数据或者新增数据之后需要重新刷新当前页面的需求. 2.遇到的问题 1. 用vue-router重新路由到当前页面,页面是不进行刷新的 2.采用window.rel ...

  8. 手把手教你创建「人物角色Persona」

    一.为什么要创建人物角色 下图来自 Cooper interaction design ,同样有购车需求的用户,用车的人不同.各自的目的不同,最终满足需求的车型也有很大差异.对于汽车公司而言,在车辆设 ...

  9. python 基础语法学习

    .注释 python单行注释以#开头 如:#!/usr/bin/env python3 #查找运行环境 多行注释有' ' '和" " " .python最具有特色的是使用 ...

  10. 查找linux设备的uuid

    [root@ ~]# blkid /dev/vdc /dev/vdc: UUID="bxxxx-xxx-41b9-8146-7da8bd645b92" TYPE="ext ...