JS观察者模式和发布订阅模式

观察者模式

观察者模式在前端工程中是很常见的设计模式,因为前端交互中充斥着大量多控件联动的交互,当参与联动的组件数量比较多或者组件数量可能变化的时候,代码就会变得难以维护。但是如果我们写代码时遵循了观察者模式的设计,便可以较好的解决以上两个痛点。

观察者模式,指的是一个主题对象(subject),维护了一个依赖它的观察者(observers)数组,当subject变化的时候,会通知数组中的观察者自动更新它自己。
简单来说就是,一个对象(被观察者)的状态发生改变时,会通知所有依赖它的对象(观察者),这两者是直接关联的。

9d50837d41bf474c6ac4f0e62296b6e9.jpeg
如图所示,当Subject(被观察者)状态发生变化时,会给所有的Observers(观察者们)发送一个通知函数,观察者们接收到通知后通常会调用各自的更新函数。

/**
 * 悬赏任务
 */
class Hunter {
  // 存储订阅的猎手需求
  demands = []
  constructor (name, intelligent, money) {
    this.name = name // 名字
    this.intelligent = intelligent // 职能
    this.money = money // 赏金
  }
  // 订阅
  subscribe (target, demand) {
    target.demands.push(demand)
  }
  // 发布
  publish (intelligent, money) {
    this.demands.forEach(demand => {
      demand(intelligent, money)
    })
  }
}
// 注册猎手
const a = new Hunter('张三', '前端开发', 5000)
const b = new Hunter('李斯', '后端开发', 5000)
const c = new Hunter('王五', '后端开发', 3000)
const boss = new Hunter('小明', '老板')
// 订阅老板
a.subscribe(boss, function(intelligent, money) {
  if (intelligent !== a.intelligent) {
    console.log('我是前端开发a,职能和我不匹配')
    return
  }
  if (money < a.money) {
    console.log('我是前端开发a,职能匹配,但是钱太少了不干')
    return
  }
  console.log('我是前端开发a, 职能和赏金都匹配')
})
b.subscribe(boss, function(intelligent, money) {
  if (intelligent !== b.intelligent) {
    console.log('我是后端开发b,职能和我不匹配')
    return
  }
  if (money < b.money) {
    console.log('我是后端开发b,职能匹配,但是钱太少了不干')
    return
  }
  console.log('我是后端开发b, 职能和赏金都匹配')
})
c.subscribe(boss, function(intelligent, money) {
  if (intelligent !== c.intelligent) {
    console.log('我是后端开发c,职能和我不匹配')
    return
  }
  if (money < c.money) {
    console.log('我是后端开发c,职能匹配,但是钱太少了不干')
    return
  }
  console.log('我是后端开发c, 职能和赏金都匹配')
})
// 老板发布悬赏
boss.publish('后端开发', 3000)
// 我是前端开发a,职能和我不匹配
// 我是后端开发b,职能匹配,但是钱太少了不干
// 我是后端开发c, 职能和赏金都匹配

发布订阅模式

发布订阅模式中,发布者发布消息时不会将消息直接发送给订阅者,发布者和订阅者之间不存在直接的联系;在发布者和订阅者之间存在第三方平台,称为消息代理或调度中心或中间件,它维持着发布者和订阅者之间的联系,可以处理所有发布者发布的消息并将它们分发给对应的订阅者,实现了发布者与订阅者之间的解耦。

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

5241362-3b0edd9d6de0df1b.png
如图所示,发布者与订阅者之间不是互相依赖和关联的,两者之间有一个通信结构(事件通道)。这个事件通道会处理发布者发布的不同类型的通知,并且将这些通知发送给相应的订阅者。

/**
 * 找年龄相同的人
 */
// 调度中心
class Topic {
  static demands = {}
  // 订阅所有需求
  static subscribe (key, demand) {
    // 对需求分类收集
    if (!Topic.demands[key]) Topic.demands[key] = []
    Topic.demands[key].push(demand)
  }
  // 对所有订阅者发布通知
  static publish (key, age) {
    if (!Topic.demands[key]) return
    for (const demand of Topic.demands[key]) {
      demand(age)
    }
  }
}
// 找对象的猎手类
class Hunter {
  constructor (name, age) {
    this.name = name // 名字
    this.age = age // 年龄
  }
  // 订阅,由调度中心将猎手需求分类并存放到全局
  subscribe (key, demand) {
    Topic.subscribe(key, demand)
  }
  // 发布,由调度中心将同分类下的需求全部触发
  publish (key, age) {
    Topic.publish(key, age)
  }
}
// 猎手注册
const aa = new Hunter('aa', 18)
const bb = new Hunter('bb', 20)
// 猎手订阅自己感兴趣的人
aa.subscribe('key', function (age) {
  if (age === aa.age) console.log(`我是aa,我们都是${age}`)
  else console.log(`我是aa,我们年龄不同`)
})
bb.subscribe('key', function (age) {
  if (age === bb.age) console.log(`我是bb,我们都是${age}`)
  else console.log(`我是bb,我们年龄不同`)
})
// 红娘注册
const red = new Hunter('red', 35)
// 红娘发布信息
red.publish('key', 20)
// 我是aa,我们年龄不同
// 我是bb,我们都是20

观察者模式和发布订阅模式的区别

alt
1.在观察者模式中,观察者是知道Subject的,Subject一直保持对观察者进行记录。然而,在发布订阅模式中,发布者和订阅者不知道对方的存在。它们只有通过消息代理进行通信。
2.在发布订阅模式中,组件是松散耦合的,正好和观察者模式相反。
3.观察者模式大多数时候是同步的,比如当事件触发,Subject就会去调用观察者的方法。而发布-订阅模式大多数时候是异步的(使用消息队列)。
4.观察者 模式需要在单个应用程序地址空间中实现,而发布-订阅更像交叉应用模式。尽管它们之间有区别,但有些人可能会说发布-订阅模式是观察者模式的变异,因为它们概念上是相似的。


在这里插入图片描述

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哚啦A孟

谢谢鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值