设计模式 - 发布订阅模式
一、概念
1、定义
发布订阅模式(Publish-Subscribe Pattern)是一种消息范式,定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。发布订阅模式属于行为型设计模式。
二、概要
1、主要角色
- 发布者(Publisher): 负责发布消息的对象,将消息发送给所有订阅者。
- 订阅者(Subscriber): 接收发布者发送的消息,并进行相应的处理。
- 消息(Message): 包含了需要传递的信息。
2、工作流程
- 发布者(Publisher):负责维护订阅者列表,接收消息并通知所有订阅者。
- 订阅者(Subscriber):订阅感兴趣的主题,接收发布者发送的消息,并进行相应的处理。
- 消息(Message):包含了需要传递的信息。
三、优缺点
1、优点
- 松耦合: 发布者和订阅者之间是松耦合的,可以独立改变。
- 可扩展性: 可以灵活地增加或删除发布者和订阅者,增加系统的灵活性。
- 消息中心: 通过消息中心的方式,可以集中管理和分发消息,方便维护。
2、缺点
- 订阅者顺序问题: 订阅者的收到消息的顺序是不确定的,可能导致消息的处理顺序问题。
- 可能引起性能问题: 如果订阅者过多或者通知方式不当,可能引起性能问题。
四、适用场景
- 当一个对象的改变需要通知其他对象,并且这些对象不需要知道具体是哪些对象时,可以使用发布订阅模式。
- 当一个对象的改变需要通知多个对象,但这些对象在运行时动态变化时,可以使用发布订阅模式。
- 当多个对象有相同的依赖关系,但是它们之间的关系并不明确时,可以使用发布订阅模式。
1)具体实例
- VUE 中事件总线(Event Bus)实现采用的是「发布订阅模式」。
- VUEX 全局状态管理:在大型应用中,使用发布-订阅模式可以实现全局状态管理。当状态发生变化时,通过发布事件通知所有相关组件,从而实现状态同步。
- 组件通信:在复杂的组件结构中,通过发布-订阅模式可以实现组件之间的通信。例如,一个组件触发某个事件,其他组件监听并执行相应的操作。
- 用户登录状态:当用户登录状态发生变化时,可以使用发布-订阅模式通知相关组件进行相应的更新,例如切换导航栏的显示内容。
- ...
五、示例代码
1、Java 示例
java
import java.util.ArrayList;
import java.util.List;
// 发布者
class Publisher {
private List<Subscriber> subscribers = new ArrayList<>();
public void addSubscriber(Subscriber subscriber) {
subscribers.add(subscriber);
}
public void removeSubscriber(Subscriber subscriber) {
subscribers.remove(subscriber);
}
public void publishMessage(String message) {
for (Subscriber subscriber : subscribers) {
subscriber.receiveMessage(message);
}
}
}
// 订阅者
class Subscriber {
private String name;
public Subscriber(String name) {
this.name = name;
}
public void receiveMessage(String message) {
System.out.println(name + " received message: " + message);
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Publisher publisher = new Publisher();
Subscriber subscriberA = new Subscriber("Subscriber A");
Subscriber subscriberB = new Subscriber("Subscriber B");
publisher.addSubscriber(subscriberA);
publisher.addSubscriber(subscriberB);
publisher.publishMessage("Hello World!");
// Output:
// Subscriber A received message: Hello World!
// Subscriber B received message: Hello World!
}
}
2、JavaScript 示例
javascript
// 发布者
class Publisher {
constructor() {
this.subscribers = []
}
addSubscriber(subscriber) {
this.subscribers.push(subscriber)
}
removeSubscriber(subscriber) {
this.subscribers = this.subscribers.filter((s) => s !== subscriber)
}
publishMessage(message) {
this.subscribers.forEach((subscriber) => subscriber.receiveMessage(message))
}
}
// 订阅者
class Subscriber {
constructor(name) {
this.name = name
}
receiveMessage(message) {
console.log(`${this.name} received message: ${message}`)
}
}
// 客户端
const publisher = new Publisher()
const subscriberA = new Subscriber('Subscriber A')
const subscriberB = new Subscriber('Subscriber B')
publisher.addSubscriber(subscriberA)
publisher.addSubscriber(subscriberB)
publisher.publishMessage('Hello World!')
// Output:
// Subscriber A received message: Hello World!
// Subscriber B received message: Hello World!