一、发布订阅者模式js
发布订阅者模式又称为观察者模式,是一种常见的软件设计模式,属于行为型模式。该模式定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知并被自动更新。
在JavaScript中,我们可以使用事件机制来实现发布订阅者模式。事件机制本质上就是一种发布订阅者模式的实现。我们可以通过事件机制来为一个事件注册回调函数,当这个事件触发时,所有注册的回调函数都会被依次调用。
class EventEmitter { constructor() { this._events = {} } on(event, callback) { if (!this._events[event]) { this._events[event] = [] } this._events[event].push(callback) } emit(event, ...args) { if (!this._events[event]) { return } this._events[event].forEach(fn => { fn.apply(this, args) }) } }
二、发布订阅者模式和观察者模式代码
发布订阅者模式和观察者模式在概念上很相似,都是建立了一种一对多的依赖关系。但是它们的实现方式有所不同。在观察者模式中,观察者对象需要直接订阅主题对象,而在发布订阅者模式中,发布者和订阅者之间则没有直接的联系,而是通过发布-订阅通道来进行通信。
下面是观察者模式和发布订阅者模式的示例代码:
//观察者模式 class Subject { constructor() { this.observers = [] } addObserver(observer) { this.observers.push(observer) } removeObserver(observer) { const index = this.observers.indexOf(observer) if (index !== -1) { this.observers.splice(index, 1) } } notify() { this.observers.forEach(observer => observer.update()) } } class Observer { constructor(name, subject) { this.name = name this.subject = subject this.subject.addObserver(this) } update() { console.log(`${this.name} has been notified`) } } const subject = new Subject() const observer1 = new Observer('observer1', subject) const observer2 = new Observer('observer2', subject) subject.notify() // 'observer1 has been notified', 'observer2 has been notified' //发布订阅者模式 class EventBus { constructor() { this.subscribers = {} } subscribe(event, callback) { if (!this.subscribers[event]) { this.subscribers[event] = [] } this.subscribers[event].push(callback) } unsubscribe(event, callback) { if (!this.subscribers[event]) { return } const index = this.subscribers[event].indexOf(callback) if (index !== -1) { this.subscribers[event].splice(index, 1) } } publish(event, ...args) { if (!this.subscribers[event]) { return } this.subscribers[event].forEach(fn => { fn.apply(this, args) }) } } const eventBus = new EventBus() const callback1 = () => console.log('callback1 is called') const callback2 = () => console.log('callback2 is called') eventBus.subscribe('test', callback1) eventBus.subscribe('test', callback2) eventBus.publish('test') // callback1 is called', 'callback2 is called' eventBus.unsubscribe('test', callback1) eventBus.publish('test') // 'callback2 is called'
三、发布订阅者模式实例代码
下面是一个发布订阅者模式的实例,我们模拟了一个购买商品的场景。当用户购买商品时,我们将触发一个名为“buy”事件,并传递商品名称和价格。购物车和订单模块可以订阅该事件,以便在用户购买商品时更新购物车和订单信息。
class EventBus { constructor() { this.subscribers = {} } subscribe(event, callback) { if (!this.subscribers[event]) { this.subscribers[event] = [] } this.subscribers[event].push(callback) } unsubscribe(event, callback) { if (!this.subscribers[event]) { return } const index = this.subscribers[event].indexOf(callback) if (index !== -1) { this.subscribers[event].splice(index, 1) } } publish(event, ...args) { if (!this.subscribers[event]) { return } this.subscribers[event].forEach(fn => { fn.apply(this, args) }) } } const eventBus = new EventBus() class Cart { constructor() { this.items = [] eventBus.subscribe('buy', this.add.bind(this)) } add(item) { this.items.push(item) console.log(`Item ${item.name} is added to the cart`) } } class Order { constructor() { this.items = [] eventBus.subscribe('buy', this.add.bind(this)) } add(item) { this.items.push(item) console.log(`Item ${item.name} is added to the order`) } } const cart = new Cart() const order = new Order() eventBus.publish('buy', { name: 'iPhone', price: '999' }) // 'Item iPhone is added to the cart', 'Item iPhone is added to the order'
四、发布订阅者模式怎么理解
发布订阅者模式是一种解耦的方式,将生产者和消费者完全解耦,使得它们之间没有直接的依赖关系。生产者和消费者之间仅仅通过一个中间件来通信。生产者将消息发布到中间件中,而消费者则从中间件中订阅消息。这种解耦方式使得系统变得更加松散,更容易扩展和维护。
发布者订阅者模式可以应用于很多地方,比如事件机制、消息队列、Redux等。在Vue.js中,也使用了类似的机制来实现组件间的通信,将组件间的通信从父子关系中解耦出来,使得组件之间具有更高的可扩展性和复用性。
五、发布订阅者模式面试题
以下是一些与发布订阅者模式相关的面试题:
1、请说出发布订阅者模式和观察者模式的区别。
答:在发布订阅者模式中,发布者和订阅者之间没有直接的联系,而是通过一个中间件来进行通信。而在观察者模式中,观察者对象需要直接订阅主题对象。
2、请说出事件机制的实现方式。
答:事件机制本质上就是一种发布订阅者模式的实现。我们可以为一个事件注册回调函数,当这个事件触发时,所有注册的回调函数都会被依次调用。
六、发布订阅者模式的实现
下面是一个基于ES6的发布订阅者模式的实现:
class EventBus { constructor() { this.subscribers = new Map() } subscribe(event, callback) { if (!this.subscribers.has(event)) { this.subscribers.set(event, []) } this.subscribers.get(event).push(callback) } unsubscribe(event, callback) { if (!this.subscribers.has(event)) { return } const index = this.subscribers.get(event).indexOf(callback) if (index !== -1) { this.subscribers.get(event).splice(index, 1) } } publish(event, ...args) { if (!this.subscribers.has(event)) { return } this.subscribers.get(event).forEach(fn => { fn.apply(this, args) }) } } const eventBus = new EventBus() eventBus.subscribe('test', () => console.log('test is called')) eventBus.publish('test') // 'test is called' eventBus.unsubscribe('test') // remove all subscribers for 'test' event
七、发布订阅者模式在Vue中的应用
在Vue.js中,组件间的通信可以通过props传递数据、事件派发和监听等方式来实现。其中事件派发和监听的机制就是基于发布订阅者模式来实现的。当组件A需要向组件B发送事件时,它会使用$emit方法来触发一个名为event的事件,并传递参数值。而组件B则需要使用$on方法来注册这个事件,并在回调函数中处理参数值。
以下是一个在Vue中使用发布订阅者模式来进行组件通信的实例:
//Parent.vue <template> <Child @eventName="handleEvent"></Child> </template> <script> import { EventBus } from '@/event-bus.js' export default { methods: { handleEvent() { // handle event here } }, mounted() { EventBus.$on('eventName', this.handleEvent) }, beforeDestroy() { EventBus.$off('eventName', this.handleEvent) } } </script> //Child.vue <template> <button @click="sendEvent">Send Event</button> </template> <script> import { EventBus } from '@/event-bus.js' export default { methods: { sendEvent() { EventBus.$emit('eventName', data) } } } </script> //event-bus.js import Vue from 'vue' export const EventBus = new Vue()