当前位置: 首页 >  网技达人 >  行为型:发布订阅模式

行为型:发布订阅模式

导读:定义.发布订阅模式是基于一个事件(主题)通道,希望接收通知的对象**Subscriber**(订阅者)通过自定义事件订阅主题,被激活事件的对象.Publisher (发布者)通过发布主题事件的方式通知订阅者 Subscriber (订阅者)对象。.简单说就是发布者与订阅者通过事件

定义

发布订阅模式是基于一个事件(主题)通道,希望接收通知的对象**Subscriber**(订阅者)通过自定义事件订阅主题,被激活事件的对象 Publisher (发布者)通过发布主题事件的方式通知订阅者 Subscriber (订阅者)对象。

简单说就是发布者与订阅者通过事件来通信 ,这里的发布者是之前观察者模式中的被观察者,订阅者是观察者模式中的观察者,他们角色定位是等价的,只不过是不同的叫法。

发布订阅与观察者模式

平时我们在微博中关注某个大v,这个大v 并不关心我这个订阅者具备什么特征,我只是通过微博这个平台关注了他,他也只是把他要分享的话题通过微博发出来,我和他之间并不存在直接的联系,然后我自动就能看到这个大v发布的消息,这就是发布订阅模式。

发布订阅者模式与观察者模式类似,但是两者并不完全相同,发布订阅者模式与观察者相比多了一个中间层事件调度中心 ,用来对发布者发布的信息进行处理,再通知到各个特定的订阅者,大致过程如下图所示

发布者只是发布某事件,无需知道哪些订阅者,订阅者只需要订阅自己感兴趣的事件,无需关注发布者。

发布者完全不用感知订阅者,不用关心它怎么实现回调方法,事件的注册和触发都发生在独立于双方的第三方平台(调度中心)上,发布- 订阅模式下,实现了完全地解耦。

通过之前对观察者模式的实现,我们的**Subject** 类中是持有**observer** 对象的,因此并没有实现两个类的完全解耦。通过添加中间层的调度中心类,我么可以将订阅者和发布者完全解耦,两者不再有直接的关联,而是通过调度中心关联起来。下面我们实现一个发布订阅者模式。

传统写法模拟发布订阅模式

按照上面思路,我们需要写下如下三个类,然后事件中心对象是发布者、订阅者之间的桥梁,我们很快写下如下代码:

  1. 发布者 —- 观察者模式中的【被观察者】

  2. 订阅者 —- 观察者模式中的【订阅者】

  3. 事件中心 —- 类似公共的一个平台

    /* 发布者:发布、注册xxx事件 or 主题 订阅者:自己的行为,取消订阅,订阅 事件中心:注册发布者的某事件、取消注册发布者的某事件、注册订阅者、取消订阅者、发布事件(通知订阅者) */ // 发布者 class Pulisher { constructor (name, evtCenter) { this.name = name; this.evtCenter = evtCenter; } // 向事件调度中心-注册某事件 register (evtName) { this.evtCenter.registerEvt(evtName) } unregister (evtName) { this.evtCenter.unRegisterEvt(evtName) } // 向事件调度中心-发布某事件 publish (evtName, …params) { this.evtCenter.publish(evtName, …params) } }

    // 订阅者 class Subscriber { constructor (name,evtCenter) { this.name = name; this.evtCenter = evtCenter; } //订阅 subscribe(evtName) { this.evtCenter.addSubscribe(evtName, this); } //取消订阅 unSubscribe(evtName) { this.evtCenter.unAddSubscribe(evtName, this); } //接收 update(params) { console.log(我接收到了,${params}); } }

    // 事件调度中心 class EvtCenter { constructor (name) { this.name = name; this.evtHandle = {} } // 注册发布者要发布的事件 registerEvt (evtName) { if (!this.evtHandle[evtName]) { this.evtHandle[evtName] = [] } } // 取消注册发布者要发布的事件 unRegisterEvt (evtName) { delete this.evtHandle[evtName]; } // 增加订阅者-注册观察者 addSubscribe(evtName, sub) { if (this.evtHandle[evtName]) { this.evtHandle[evtName].push(sub); } } // 取消订阅者-移除注册观察者 unAddSubscribe(evtName, sub) { this.evtHandle[evtName].forEach((item, index) => { if (item === sub) { this.evtHandle[evtName].splice(index, 1); } }); }

    // 事件调度中心-发布某事件 publish (evtName, …params) { this.evtHandle[evtName] && this.evtHandle[evtName].forEach((item) => { item.update(…params); }); } }

    // 测试 const evtCenter1 = new EvtCenter(‘报社调度中心1’)

    const pulisher1 = new Pulisher(‘报社1’, evtCenter1)

    const sub1 = new Subscriber(‘我是sub1, 我对日报感兴趣’, evtCenter1) const sub2 = new Subscriber(‘我是sub2, 我对日报感兴趣’, evtCenter1) const sub3 = new Subscriber(‘我是sub3, 我对中报感兴趣’, evtCenter1) const sub4 = new Subscriber(‘我是sub4, 我对晚报感兴趣’, evtCenter1)

    // 发布者-注册三个事件到事件中心 pulisher1.register(‘广州日报’) pulisher1.register(‘广州中报’) pulisher1.register(‘广州晚报’)

    // 订阅者可以自己订阅,当然也可以直接操作事件中心 sub1.subscribe(‘广州日报’) sub2.subscribe(‘广州日报’) sub3.subscribe(‘广州中报’) sub4.subscribe(‘广州晚报’)

    // 现在开始发布事件 pulisher1.publish(‘广州日报’, ‘广州日报’) pulisher1.publish(‘广州中报’, ‘广州中报’) pulisher1.publish(‘广州晚报’, ‘广州晚报’)

    pulisher1.unregister(‘广州日报’)

    // 再一次发布事件 console.log(‘再一次发布事件,这次我取消了日报’) // 没有输出广州日报 pulisher1.publish(‘广州日报’, ‘广州日报’) pulisher1.publish(‘广州中报’, ‘广州中报’) pulisher1.publish(‘广州晚报’, ‘广州晚报’)

简单写法–面向事件调度中心编程

在js中函数是第一等公民,天生适合回调函数,所以可以直接面向事件调度中心编码即可。我们要做的事情其实就是触发什么事件,执行什么动作。

// 事件调度中心
class PubSub  {
  constructor () {
    this.evtHandles = {}
  }
  // 订阅
  subscribe (evtName, callback) {
    if (!this.evtHandles[evtName]) {
      this.evtHandles[evtName] = [callback];
    }
    this.evtHandles[evtName].push(callback);
  }
  // 发布
  publish(evtName, ...arg) {
    if (this.evtHandles[evtName]) {
      for(let fn of this.evtHandles[evtName]) {
        fn.call(this, ...arg);
      }
    }
  }
  unSubscribe (evtName, fn) {     // 取消订阅
    let fnList = this.evtHandles[evtName];
    if (!fnList) return false;

    if (!fn) {
      // 不传入指定取消的订阅方法,则清空所有key下的订阅
      this.evtHandles[evtName] = []
    } else {
      fnList.forEach((item, index) => {
        if (item === fn) {
          fnList.splice(index, 1);
        }
      })
    }
  }
}
// 先订阅在发布
const pub1 = new PubSub()

// 订阅三个事件
pub1.subscribe('onWork', time => {
  console.log(`上班了:${time}`);
})
pub1.subscribe('onWork', time => {
  console.log(`上班了:${time},开始打开待办事项`);
})

pub1.subscribe('onOffWork', time => {
  console.log(`下班了:${time}`);
})

pub1.subscribe('onLaunch', time => {
  console.log(`吃饭了:${time}`);
})

// 发布对应的事件
pub1.publish('onWork', '09:00:00');
pub1.publish('onLaunch', '12:00:00');
pub1.publish('onOffWork', '18:00:00');
// 取消onWork 事件
pub1.unSubscribe('onWork');


// 取消订阅
pub1.unSubscribe('onWork');
console.log(`取消 onWork`);
pub1.publish('onWork', '09:00:00'); // 不会执行

小结

  1. 发布者不直接触及到订阅者、而是由统一的第三方来完成实际的通信的操作,叫做发布订阅模式
  2. 发布者(被观察者)直接操作订阅者的操作,叫做观察者模式
  3. 发布订阅模式,发布者完全不用感知订阅者,不用关心它怎么实现回调方法,事件的注册和触发都发生在独立于双方的第三方平台(事件调度中心)上,发布-订阅模式下,实现了完全地解耦。
  4. 发布订阅核心通过事件来通信,在调度中心中派发给具体的订阅者。
内容
  • GitHub Actions 入门指南
    GitHub Actions 入
    2023-12-12
    前言.GitHub Actions 可以构建一组自动化的工作流程,并提供了拉取请求、合并分支等事件来触发他们。一般成熟的
  • 青语言开源发布
    青语言开源发布
    2023-12-10
    青语言发布.6月1日,在这个充满欢声笑语的日子里,数心开物工作室开源发布了一门面向青少年、儿童和非专业人士的中文编程语言
  • 高效联调,可靠发布!华为云推出CodeArts Release发布管理服务
    高效联调,可靠发布!华为云推出C
    2023-12-09
    摘要: 华为云全新推出CodeArts.Release发布管理服务,旨在将华为多年形成的发布实践外溢,帮助企业提升软件发
  • Kurator v0.3.0版本发布
    Kurator v0.3.0版本
    2023-12-08
    摘要: 2023年4月8日,Kurator正式发布v0.3.0版本。.本文分享自华为云社区《华为云 Kurator v0
  • 企业研发治理转型利器:华为云发布流水线服务CodeArts Pipeline
    企业研发治理转型利器:华为云发布
    2023-12-06
    摘要: 2月27日,华为云正式发布流水线服务CodeArts.Pipeline,旨在提升编排体验,开放插件平台,以及提供
  • 旋转网格超采样(Rotated Grid Supersampling)
    旋转网格超采样(Rotated
    2023-12-06
    旋转网格超采样(Rotated Grid Supersampling).这是对文章 4-Rook Antialiasin
  • 4.7 x64dbg 应用层的钩子扫描
    4.7 x64dbg 应用层的钩
    2023-12-06
    所谓的应用层钩子(Application-level.hooks)是一种编程技术,它允许应用程序通过在特定事件发生时执行
  • 休闲简约短袖衬衫
    休闲简约短袖衬衫
    2023-12-21
    休闲简约短袖衬衫.现代人生活节奏快,休闲简约的穿着成为时尚潮流。短袖衬衫作为经典的休闲单品,一直备受时尚人士的青睐。它舒
  • 时尚牛仔裤,展现随性休闲风格
    时尚牛仔裤,展现随性休闲风格
    2024-01-10
    时尚牛仔裤,展现随性休闲风格.时尚牛仔裤一直是时装界的宠儿,它不仅兼具舒适与时尚,更能展现出一种随性的休闲风格。无论是搭
  • 时尚商务西服套装
    时尚商务西服套装
    2023-12-16
    时尚商务西服套装.时尚商务西服套装一直是职场男士们必备的时尚单品之一。无论是商务会议、重要场合还是日常办公,一套精致的商
  • 轻盈雪纺衬衫,打造清新淑女形象
    轻盈雪纺衬衫,打造清新淑女形象
    2023-12-31
    轻盈雪纺衬衫,打造清新淑女形象.雪纺材质的衬衫一直以来都是清新淑女形象的代表,它轻盈飘逸的质地,柔软透气的触感,让人仿佛
  • 精美儿童连衣裙,时尚设计,舒适面料,适合各种场合穿着
    精美儿童连衣裙,时尚设计,舒适面
    2023-12-26
    精美儿童连衣裙,时尚设计,舒适面料,适合各种场合穿着.儿童连衣裙作为孩子们的日常穿着之一,一直备受家长们的关注。精美儿童
  • 时尚潮流运动鞋
    时尚潮流运动鞋
    2024-01-15
    时尚潮流运动鞋.时尚潮流运动鞋一直是年轻人喜爱的时尚单品,它不仅舒适耐穿,更是一种个性的象征。随着时尚潮流不断更新,运动
  • 保暖舒适羊毛大衣
    保暖舒适羊毛大衣
    2024-01-05
    保暖舒适羊毛大衣.冬季来临,寒冷的天气让人们更加注重保暖。在这个时候,一件保暖舒适的羊毛大衣成为了许多人的首选。羊毛大衣
  • 时尚个性针织毛衣
    时尚个性针织毛衣
    2023-12-11
    时尚个性针织毛衣.时尚个性针织毛衣一直是秋冬季节的必备单品,不仅可以很好地保暖,还能展现出个性与时尚。无论是女性还是男性
  • 经典款皮鞋
    经典款皮鞋
    2023-12-06
    经典款皮鞋.经典款皮鞋一直是时尚界的永恒之选,不论是商务场合、休闲聚会还是正式场合,都能展现出绅士淑女的气质和优雅。今天
  • 精致绣花针织衫,增添浪漫风情
    精致绣花针织衫,增添浪漫风情
    2023-12-01
    精致绣花针织衫,增添浪漫风情.如今,针织衫已成为时尚界不可或缺的一部分,而精致绣花针织衫更是备受追捧。其独特的设计和精湛