设计模式-发布订阅模式(javaScript)

  • 1. 前言
  • 2. 什么是发布订阅模式
  • 3. 发布订阅优缺点
  • 4. 举例
  • 4. 总结

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可以为员工分配不同的工作,即时需要添加工作类与类之间没有任何沟耦合性。各自维护自己,任意一个类发生变化都不会互相影响。

总结

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

原文地址:https://www.cnblogs.com/aaron---blog/p/10548336.html

时间: 2024-10-09 15:27:06

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

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

直接上代码: index.html : <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>设计模式</title> </head> <body> <div id="box"> <div>{{message}}</div> <

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

最近拜读了曾探所著的<JavaScript设计模式与开发应用>一书,在读到发布-订阅模式一章时,作者不仅给出了基本模式的通用版本的发布-订阅模式的代码,最后还做出了扩展,给该模式增加了离线空间功能和命名空间功能,以达到先发布再订阅的功能和防止名称冲突的效果.但是令人感到遗憾的是最终代码并没有给出足够的注释.这让像我一样的小白就感到非常的困惑,于是我将这份最终代码仔细研究了一下,并给出了自己的一些理解,鉴于能力有限,文中观点可能并不完全正确,望看到的大大们不吝赐教,谢谢! 下面是添加了个人注释的

JavaScript设计模式与开发实践---读书笔记(8) 发布-订阅模式

发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. 发布-订阅模式可以广泛应用于异步编程中,这是一种替代传递回调函数的方案. 可以取代对象之间硬编码的通知机制,一个对象不用再显式地调用另外一个对象的某个接口. 自定义事件 首先要指定好谁充当发布者: 然后给发布者添加一个缓存列表,用于存放回调函数以便通知订阅者: 最后发布消息时,发布者会遍历这个缓存列表,依次触发里面存放的订阅者回调函数. 另外,我们还可以往回调函数里填入

javascript设计模式学习之八_发布订阅模式

一.发布订阅模式定义 发布订阅模式又叫做观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知.发布—订阅模式可以取消对象之间硬编码的通知机制.javascript中的事件机制就属于发布订阅模式的一种. 二.发布订阅模式使用案例 2.1网站登录 假设正在开发一个网站,网站里面有header头部,nav导航,消息列表,购物车等模块,

JavaScript设计模式之----原生JS实现简单的发布订阅模式

第一部分: 发布订阅模式简介 发布—订阅模式又叫观察者模式,它定义对象间的一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知.在javascript开发中,一般用事件模型来替代传统的发布—订阅模式. 发布—订阅模式可以广泛应用于异步编程中,是一种替代传递回调函数的方案.比如,可以订阅ajax请求的error.success等事件.或者如果想在动画的每一帧完成之后做一些事情,可以订阅一个事件,然后在动画的每一帧完成之后发布这个事件.在异步编程中使用发布—订阅模式,就无需过

Javascript设计模式之发布-订阅模式

简介 发布-订阅模式又叫做观察者模式,他定义了一种一对多的依赖关系,即当一个对象的状态发生改变的时候,所有依赖他的对象都会得到通知. 回忆曾经 作为一名前端开发人员,给DOM节点绑定事件可是再频繁不过的事情.比如如下代码 document.body.addEventListener('click',function () { alert(2333); },false); document.body.click();//模拟点击事件 这里我们订阅了document.body的click事件,当bo

设计模式 - 发布-订阅者模式

1.发布-订阅者 设计模式 定义 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知 观察者模式和发布订阅模式区别 观察者模式是由具体目标(发布者/被观察者)调度的,而发布/订阅模式是由独立的调度中心进行调度,所以观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会:可以说发布订阅模式是观察者模式进一步解耦,在实际中被大量运用的一种模式 ** 观察者模式 ** 1.定义/解析 目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更

[转] 浅析JavaScript设计模式——发布-订阅/观察者模式

前一段时间一直在写CSS3的文章 一直都没写设计模式 今天来写写大名鼎鼎观察者模式 先画张图 观察者模式的理解 我觉得还是发布-订阅模式的叫法更容易我们理解 (不过也有的书上认为它们是两种模式……) 这就类似我们在微信平台订阅了公众号 当它有新的文章发表后,就会推送给我们所有订阅的人 我们可以看到例子中这种模式的优点 我们作为订阅者不必每次都去查看这个公众号有没有新文章发布, 公众号作为发布者会在合适时间通知我们 我们与公众号之间不再强耦合在一起.公众号不关心谁订阅了它, 不管你是男是女还是宠物

设计模式--观察者模式(发布订阅模式)

观察者模式又叫做发布—订阅模式,是我们最常用的设计模式之一.它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知和更新. 观察者模式提供了一个订阅模型,其中对象订阅事件并在发生时得到通知,这种模式是事件驱动的编程基石,它有利益于良好的面向对象的设计. 从上面的话语我们可以得知,观察者模式主要动力是促进形成松散耦合(解耦). 设计思路: 首先先声明一个观察者对象 // 注册观察者对象 var Observer = (function (){ var Oms