557 字
3 分钟
观察者模式和发布订阅区别
【观察者模式】和【发布订阅】 区别
思考一下邮件系统业务流程
1、观察者模式

组成:
- 两个角色:观察者与被观察者
实现:
- 被观察者
class Subject { constructor() { this.observerList = []; }
addObserver(observer) { this.observerList.push(observer); }
removeObserver(observer) { const index = this.observerList.findIndex((o) => o.name === observer.name); this.observerList.splice(index, 1); }
notifyObservers(message) { const observers = this.observeList; observers.forEach((observer) => observer.notified(message)); }}- 观察者
class Observer { constructor(name, subject) { this.name = name; if (subject) { subject.addObserver(this); } }
notified(message) { console.log(this.name, "got message", message); }}- 使用
const subject = new Subject();const observerA = new Observer("observerA", subject);const observerB = new Observer("observerB");subject.addObserver(observerB);subject.notifyObservers("Hello from subject");subject.removeObserver(observerA);subject.notifyObservers("Hello again");- 解析
- 观察者主动申请加入被观察者的列表
- 被观察者主动将观察者加入列表
2、发布订阅

组成:
- 至少三个角色:发布者、订阅者、发布订阅中心
实现:
- 发布订阅中心
class PubSub { constructor() { this.messages = {}; this.listeners = {}; } publish(type, content) { const existContent = this.messages[type]; if (!existContent) { this.messages[type] = []; } this.messages[type].push(content); } subscribe(type, cb) { const existListener = this.listeners[type]; if (!existListener) { this.listeners[type] = []; } this.listeners[type].push(cb); } notify(type) { const messages = this.messages[type]; const subscribers = this.listeners[type] || []; subscribers.forEach((cb, index) => cb(messages[index])); }}
- 发布者
class Publisher { constructor(name, context) { this.name = name; this.context = context; } publish(type, content) { this.context.publish(type, content); }}- 订阅者
class Subscriber { constructor(name, context) { this.name = name; this.context = context; } subscribe(type, cb) { this.context.subscribe(type, cb); }}- 使用
const TYPE_A = "music";const TYPE_B = "movie";const TYPE_C = "novel";
const pubsub = new PubSub();
const publisherA = new Publisher("publisherA", pubsub);publisherA.publish(TYPE_A, "we are young");publisherA.publish(TYPE_B, "the silicon valley");const publisherB = new Publisher("publisherB", pubsub);publisherB.publish(TYPE_A, "stronger");const publisherC = new Publisher("publisherC", pubsub);publisherC.publish(TYPE_C, "a brief history of time");
const subscriberA = new Subscriber("subscriberA", pubsub);subscriberA.subscribe(TYPE_A, (res) => { console.log("subscriberA received", res);});const subscriberB = new Subscriber("subscriberB", pubsub);subscriberB.subscribe(TYPE_C, (res) => { console.log("subscriberB received", res);});const subscriberC = new Subscriber("subscriberC", pubsub);subscriberC.subscribe(TYPE_B, (res) => { console.log("subscriberC received", res);});
pubsub.notify(TYPE_A);pubsub.notify(TYPE_B);pubsub.notify(TYPE_C);- 解析
- 发布者和订阅者实现比较简单,只需完成各自发布、订阅的任务即可
- 重点在于二者需要确保在与同一个发布订阅中心进行关联,否则两者之间的通信无从关联。
- 发布者的发布动作和订阅者的订阅动作相互独立,无需关注对方业务,消息派发由发布订阅中心负责。
实际应用
- Node.js 中自带的 EventEmiter 模块
- Vue.js 中数据响应式的实现