---theme: theme-orange ---
再前面两章,我们分别学习了发布订阅、观察者模式。恰巧最近再面试的过程中遇到了相关问题,于是在我略施拳脚后成功**说服(shuì fú)
**了面试官。
面试现场
🙎🏻♀️ HR小姐姐: 你是来参加面试的吧?
🤵🏻 我: 是的,我昂起头,自信地点了点头。
🙎🏻♀️ HR小姐姐: 面试官马上就来,我先带你去会议室。
会议室
🙎🏻♀️ HR小姐姐: 面试官临时有个会议,你稍等一会儿。
👨🏻💼 面试官走进来:
你是杰克马是吧?
🤵🏻 我:
你好,面试管。我叫马杰克,那名字可不敢叫,那不是僭越了嘛。
👨🏻💼 面试官: 你小子,还是有分寸的,我们开始面试,你简单介绍一下自己。
🤵🏻 我: 好的,我开始自信地介绍自己。
👨🏻💼 面试官: 挑一个你最熟悉的技能说说。
🤵🏻 我: (PS:你小子这不是踢钢板上了么)我最近正在阅读
《Head First 设计模式》
,想谈谈设计模式。
👨🏻💼 面试官: 那你说说观察者模式和发布订阅模式的区别吧。
于是就有了下面的内容
发布订阅(Publish-Subscribe)和观察者(Observer)模式都是设计模式中常用的通信模式,用于实现对象间的解耦和事件处理。
- 发布订阅模式:在这种模式中,发布者和订阅者之间没有直接依赖关系。它们通过一个中介(消息代理或事件总线)进行通信。发布者发布消息到消息代理,订阅者从消息代理订阅消息。这样,发布者和订阅者不需要知道对方的存在。
- 观察者模式:在这种模式中,观察者和被观察者(也叫主题)之间存在直接依赖关系。观察者注册自己感兴趣的主题,然后等待主题的通知。主题维护一个观察者列表,当状态改变时,主题会通知列表中的观察者。
这种概念的性的描述不利于记忆,我们举个例子说明一下,我有一个朋友叫英俊,他酷爱洗澡。
发布订阅模式
- 场景描述:洗浴中心通过合作饭店进行促销活动,饭店的顾客在满足一定条件下可以以优惠价格购买洗浴中心的年卡。洗浴中心通过这种方式吸引新客户,并通过客户的口碑传播进一步增加客户基数。
在这个例子中,洗浴中心可以视为“发布者”,而饭店的顾客可以视为“订阅者”。洗浴中心发布优惠信息(发布),饭店的顾客通过饭店得知优惠信息并选择购买(订阅)。这种模式实现了洗浴中心和顾客之间的解耦,洗浴中心不需要直接与每个顾客沟通,而是通过饭店这个中介来发布信息。
观察者模式
- 场景描述:洗浴中心通过观察顾客的使用频率和偏好,来调整服务和营销策略。例如,如果某个顾客经常来洗浴中心,洗浴中心可能会针对这位顾客提供个性化的服务或优惠。
在这个例子中,洗浴中心可以视为“被观察者”,而顾客可以视为“观察者”。洗浴中心通过观察顾客的行为(使用频率和偏好)来调整自己的服务策略,而顾客则通过自己的行为影响洗浴中心的服务提供。这种模式实现了洗浴中心和顾客之间的紧密互动,但保持了各自的独立性。
如果还没懂,这边建议您先去洗个澡,清醒一下。
发布订阅模式(Publish-Subscribe)
- 参与者:包括发布者(Publisher)、订阅者(Subscriber)和消息代理(Message Broker)。
- 结构:发布者和订阅者通过消息代理进行通信,发布者将消息发送到消息代理,消息代理将消息分发给订阅者。
- 解耦:发布者和订阅者之间完全解耦,彼此不知道对方的存在,只需通过消息代理进行消息传递。
- 使用场景:适用于系统中有大量松散耦合的组件,需要进行复杂的事件传递和处理,例如事件驱动系统、日志收集、通知系统等。
- 实现方式:通常通过消息队列(如RabbitMQ、Kafka)或事件总线(如EventBus)来实现。
观察者模式(Observer)
- 参与者:包括被观察者(Subject)和观察者(Observer)。
- 结构:被观察者维护一个观察者列表,当被观察者状态发生变化时,通知所有观察者。
- 耦合度:观察者和被观察者之间存在一定的耦合,观察者需要注册到被观察者中,被观察者知道观察者的存在。
- 使用场景:适用于一个对象状态变化需要通知多个对象的场景,例如GUI应用中的事件监听、数据模型与视图同步等。
- 实现方式:通常通过直接的对象引用和方法调用来实现,比较简单。
对比总结
特性 | 发布订阅模式 | 观察者模式 |
---|---|---|
参与者 | 发布者、订阅者、消息代理 | 被观察者、观察者 |
结构 | 通过消息代理进行消息传递 | 被观察者直接通知观察者 |
解耦程度 | 发布者和订阅者完全解耦 | 被观察者和观察者之间有一定耦合 |
通信方式 | 异步(通过消息队列或事件总线) | 同步(通过方法调用) |
使用场景 | 事件驱动系统、大规模分布式系统 | GUI事件监听、模型视图同步等小规模系统 |
实现复杂度 | 较高,需要引入消息代理或事件总线 | 较低,通过对象引用和方法调用实现 |
发布订阅模式
class MessageBroker:
def __init__(self):
self.subscribers = {}
def subscribe(self, event_type, subscriber):
if event_type not in self.subscribers:
self.subscribers[event_type] = []
self.subscribers[event_type].append(subscriber)
def publish(self, event_type, data):
if event_type in self.subscribers:
for subscriber in self.subscribers[event_type]:
subscriber.update(data)
class Subscriber:
def update(self, data):
print(f"Received data: {data}")
broker = MessageBroker()
subscriber = Subscriber()
broker.subscribe("event", subscriber)
broker.publish("event", "Hello, World!")
观察者模式
class Subject:
def __init__(self):
self.observers = []
def attach(self, observer):
self.observers.append(observer)
def detach(self, observer):
self.observers.remove(observer)
def notify(self, data):
for observer in self.observers:
observer.update(data)
class Observer:
def update(self, data):
print(f"Observer received data: {data}")
subject = Subject()
observer = Observer()
subject.attach(observer)
subject.notify("Hello, World!")
发布订阅模式
报纸订阅
- 发布者:报社
- 订阅者:读者
- 消息代理:邮局
过程:
- 读者(订阅者)通过邮局(消息代理)订阅了某个报社(发布者)的报纸。
- 每天,报社会把最新的报纸送到邮局。
- 邮局根据订阅信息,将报纸分发给所有订阅的读者。
报社并不知道具体有谁订阅了报纸,它只负责把报纸交给邮局,邮局负责管理订阅信息和分发报纸。读者和报社之间没有直接联系,它们通过邮局进行通信。
观察者模式
班主任和学生
- 被观察者:班主任
- 观察者:学生
过程:
- 班主任(被观察者)在班级中宣布了一条重要通知。
- 每个学生(观察者)都在听班主任的通知。
- 班主任说完通知后,所有学生都收到了这条通知。
班主任知道哪些学生在听通知,并且直接将通知传达给他们。学生和班主任之间有直接的联系,学生需要注册到班主任的通知列表中才能接收通知。
对比总结
- 发布订阅模式(报纸订阅):报社(发布者)和读者(订阅者)之间完全解耦,通过邮局(消息代理)进行通信。
- 观察者模式(班主任和学生):班主任(被观察者)直接通知学生(观察者),彼此之间有直接联系。
👨🏻💼 面试官: 你对观察者模式和发布订阅模式的理解非常的透彻,整的表现也非常的出色,后续HR会与你联系,回去等结果通知