JavaScript - 观察者与发布订阅者模式
观察者模式
- 观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有
依赖者
都会收到通知并自动更新。 - 当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
- 可以看作
拍卖场景
,拍卖师观察最高标价,然后通知给其他竞价者竞价。
- 观察者和被观察者是抽象耦合的,实现简单,主题和观察者之间的关系明确,适用于一对多的关系。
- 当观察者较多时,主题的通知机制可能会导致性能问题,因为每个观察者都会被直接通知。
具体实现
观察者javascript
12345678class Observer {constructor(name) {this.name = name}update(data) {console.log(`观察者${this.name} 收到了: ${data}`)}}
被观察者javascript
1234567891011121314class Subject {constructor() {this.observers = []}add(observer) {this.observers.push(observer)}notify(data) {this.observers.forEach((i) => i.update(data))}delete(observer) {this.observers = this.observers.filter((i) => i !== observer)}}
具体使用
一个栗子javascript
123456789101112131415const sub = new Subject()const observer1 = new Observer('A')const observer2 = new Observer('B')sub.add(observer1)sub.add(observer2)sub.notify('一条新闻')// 观察者A 收到了: 一条新闻// 观察者B 收到了: 一条新闻sub.notify('今天的天气是晴天')// 观察者A 收到了: 今天的天气是晴天// 观察者B 收到了: 今天的天气是晴天sub.delete(observer1)
发布订阅者模式
- 发布/订阅(Publish–subscribe pattern)是一种消息范式,消息的
发送者
(称为发布者)不会将消息直接发送给特定的接收者
(称为订阅者)。 - 而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在。同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者(如果有的话)存在。
- 可以看作一个为
邮件系统
,你可以作为订阅者
订阅某个网站的通知,邮件系统在其中充当发布订阅中心
的角色,而发布者
则是你订阅的网站。
- 解耦发布者和订阅者,使得系统更灵活,扩展性更好;支持多对多的关系,可以实现更复杂的消息通信。
- 引入了调度中心,可能会增加系统的复杂度;由于间接通信,调试和理解代码可能会稍微困难一些。
具体实现
调度中心javascript
12345678910111213141516171819202122232425262728class Dep {constructor() {this.subscriptions = {}}subscribe(topic, callback) {if (!this.subscriptions[topic]) {this.subscriptions[topic] = []}this.subscriptions[topic].push(callback)}unSubscribe(topic) {if (!this.subscriptions[topic]) {return}delete this.subscriptions[topic]}publish(topic, data) {if (!this.subscriptions[topic]) {return}this.subscriptions[topic].forEach((callback) => {callback(data)})}}
发布者javascript
123456789class Publisher {constructor(pub) {this.pub = pub}publishMessage(topic, message) {this.pub.publish(topic, message)}}
订阅者javascript
123456789101112131415161718class Subscriber {constructor(sub, name) {this.sub = subthis.name = name}subscribeToTopic(topic) {this.sub.subscribe(topic, (data) => {console.log(`订阅者 ${this.name} 收到${topic}消息: ${data}`)})}unSubscribeToTopic(topic) {this.sub.unSubscribe(topic, (data) => {console.log(`订阅者 ${this.name} 取消订阅${topic}消息: ${data}`)})}}
具体使用
一个栗子🌰javascript
12345678910111213141516const dep = new Dep()const publisher = new Publisher(dep)const subscriber1 = new Subscriber(dep, 'A')const subscriber2 = new Subscriber(dep, 'B')subscriber1.subscribeToTopic('news')subscriber2.subscribeToTopic('weather')publisher.publishMessage('news', '一条新闻')// 订阅者 A 收到news消息: 一条新闻publisher.publishMessage('weather', '今天的天气是晴天')// 订阅者 B 收到weather消息: 今天的天气是晴天subscriber1.unSubscribeToTopic('news')