面试大揭秘:发布订阅与观察者模式的区别

举报
不惑 发表于 2024/12/06 14:27:35 2024/12/06
【摘要】 发布订阅(Publish-Subscribe)和观察者(Observer)模式都是设计模式中常用的通信模式,用于实现对象间的解耦和事件处理。

再前面两章,我们分别学习了发布订阅观察者模式。恰巧最近再面试的过程中遇到了相关问题,于是在我略施拳脚后成功**说服(shuì fú)**了面试官。

面试现场

🙎🏻‍♀️ **HR小姐姐:**你是来参加面试的吧?
🤵🏻 **我:**是的,我昂起头,自信地点了点头。
🙎🏻‍♀️ **HR小姐姐:**面试官马上就来,我先带你去会议室。

会议室

🙎🏻‍♀️ HR小姐姐:面试官临时有个会议,你稍等一会儿。
👨🏻‍💼 面试官走进来:_
你是杰克马是吧?
_
🤵🏻 我:你好,面试管。我叫马杰克,那名字可不敢叫,那不是僭越了嘛。
👨🏻‍💼 **面试官:**你小子,还是有分寸的,我们开始面试,你简单介绍一下自己。
🤵🏻 **我:**好的,我开始自信地介绍自己。
👨🏻‍💼 **面试官:**挑一个你最熟悉的技能说说。
🤵🏻 我:(PS:你小子这不是踢钢板上了么)我最近正在阅读《Head First 设计模式》,想谈谈设计模式。
👨🏻‍💼 **面试官:**那你说说观察者模式和发布订阅模式的区别吧。

于是就有了下面的内容

理解概念

发布订阅(Publish-Subscribe)和观察者(Observer)模式都是设计模式中常用的通信模式,用于实现对象间的解耦和事件处理。

  • 发布订阅模式:在这种模式中,发布者和订阅者之间没有直接依赖关系。它们通过一个中介(消息代理或事件总线)进行通信。发布者发布消息到消息代理,订阅者从消息代理订阅消息。这样,发布者和订阅者不需要知道对方的存在。
  • 观察者模式:在这种模式中,观察者和被观察者(也叫主题)之间存在直接依赖关系。观察者注册自己感兴趣的主题,然后等待主题的通知。主题维护一个观察者列表,当状态改变时,主题会通知列表中的观察者。

这种概念的性的描述不利于记忆,我们举个例子说明一下,我有一个朋友叫英俊,他酷爱洗澡。

发布订阅模式

  • 场景描述:洗浴中心通过合作饭店进行促销活动,饭店的顾客在满足一定条件下可以以优惠价格购买洗浴中心的年卡。洗浴中心通过这种方式吸引新客户,并通过客户的口碑传播进一步增加客户基数。

在这个例子中,洗浴中心可以视为“发布者”,而饭店的顾客可以视为“订阅者”。洗浴中心发布优惠信息(发布),饭店的顾客通过饭店得知优惠信息并选择购买(订阅)。这种模式实现了洗浴中心和顾客之间的解耦,洗浴中心不需要直接与每个顾客沟通,而是通过饭店这个中介来发布信息。

观察者模式

  • 场景描述:洗浴中心通过观察顾客的使用频率和偏好,来调整服务和营销策略。例如,如果某个顾客经常来洗浴中心,洗浴中心可能会针对这位顾客提供个性化的服务或优惠。

在这个例子中,洗浴中心可以视为“被观察者”,而顾客可以视为“观察者”。洗浴中心通过观察顾客的行为(使用频率和偏好)来调整自己的服务策略,而顾客则通过自己的行为影响洗浴中心的服务提供。这种模式实现了洗浴中心和顾客之间的紧密互动,但保持了各自的独立性。

如果还没懂,这边建议您先去洗个澡,清醒一下。

结构对比

发布订阅模式(Publish-Subscribe)

  1. 参与者:包括发布者(Publisher)、订阅者(Subscriber)和消息代理(Message Broker)。
  2. 结构:发布者和订阅者通过消息代理进行通信,发布者将消息发送到消息代理,消息代理将消息分发给订阅者。
  3. 解耦:发布者和订阅者之间完全解耦,彼此不知道对方的存在,只需通过消息代理进行消息传递。
  4. 使用场景:适用于系统中有大量松散耦合的组件,需要进行复杂的事件传递和处理,例如事件驱动系统、日志收集、通知系统等。
  5. 实现方式:通常通过消息队列(如RabbitMQ、Kafka)或事件总线(如EventBus)来实现。

观察者模式(Observer)

  1. 参与者:包括被观察者(Subject)和观察者(Observer)。
  2. 结构:被观察者维护一个观察者列表,当被观察者状态发生变化时,通知所有观察者。
  3. 耦合度:观察者和被观察者之间存在一定的耦合,观察者需要注册到被观察者中,被观察者知道观察者的存在。
  4. 使用场景:适用于一个对象状态变化需要通知多个对象的场景,例如GUI应用中的事件监听、数据模型与视图同步等。
  5. 实现方式:通常通过直接的对象引用和方法调用来实现,比较简单。

image.png

对比总结

特性 发布订阅模式 观察者模式
参与者 发布者、订阅者、消息代理 被观察者、观察者
结构 通过消息代理进行消息传递 被观察者直接通知观察者
解耦程度 发布者和订阅者完全解耦 被观察者和观察者之间有一定耦合
通信方式 异步(通过消息队列或事件总线) 同步(通过方法调用)
使用场景 事件驱动系统、大规模分布式系统 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!")

image.png

观察者模式

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!")

image.png

日常生活示例

发布订阅模式

报纸订阅

  1. 发布者:报社
  2. 订阅者:读者
  3. 消息代理:邮局

过程

  • 读者(订阅者)通过邮局(消息代理)订阅了某个报社(发布者)的报纸。
  • 每天,报社会把最新的报纸送到邮局。
  • 邮局根据订阅信息,将报纸分发给所有订阅的读者。

报社并不知道具体有谁订阅了报纸,它只负责把报纸交给邮局,邮局负责管理订阅信息和分发报纸。读者和报社之间没有直接联系,它们通过邮局进行通信。

观察者模式

班主任和学生

  1. 被观察者:班主任
  2. 观察者:学生

过程

  • 班主任(被观察者)在班级中宣布了一条重要通知。
  • 每个学生(观察者)都在听班主任的通知。
  • 班主任说完通知后,所有学生都收到了这条通知。

班主任知道哪些学生在听通知,并且直接将通知传达给他们。学生和班主任之间有直接的联系,学生需要注册到班主任的通知列表中才能接收通知。
image.png

对比总结

  • 发布订阅模式(报纸订阅):报社(发布者)和读者(订阅者)之间完全解耦,通过邮局(消息代理)进行通信。
  • 观察者模式(班主任和学生):班主任(被观察者)直接通知学生(观察者),彼此之间有直接联系。

最后

👨🏻‍💼 **面试官:**你对观察者模式和发布订阅模式的理解非常的透彻,整的表现也非常的出色,后续HR会与你联系,回去等结果通知

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。