讲师中心 微信公众号
AI工具推荐 视频效率加速

Python中如何实现观察者模式?观察者模式如何解耦?

陌丽大大_1395

陌丽大大_1395

发布时间:2025-06-30 16:49:06

|

339人浏览过

|

来源于php中文网

原创

观察者模式常见于事件处理系统、gui框架、消息队列和mvc架构。例如,gui中的按钮点击作为主题,监听函数作为观察者;股票交易系统中,股票价格变动为主题,投资者为观察者。应用场景包括:1. 事件驱动系统;2. 用户界面组件通信;3. 消息传递机制;4. 数据模型与视图同步更新。避免循环依赖可通过弱引用、引入中间层、限制通知范围、事件过滤等方式实现。区别方面,观察者模式主题直接通知观察者,耦合度较高;而发布/订阅模式通过消息代理通信,解耦更彻底,适用于异步复杂场景。两种模式的选择取决于对耦合度和灵活性的需求。

Python中如何实现观察者模式?观察者模式如何解耦?

Python中实现观察者模式,核心在于定义一个主题(Subject)类,维护一个观察者(Observer)列表,并在主题状态改变时通知所有观察者。解耦的关键在于,主题和观察者之间通过抽象接口进行交互,而不是具体实现,从而降低它们之间的依赖性。

Python中如何实现观察者模式?观察者模式如何解耦?

解决方案

观察者模式是一种行为设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象的状态发生改变时,会通知所有观察者对象,使它们能够自动更新。

Python中如何实现观察者模式?观察者模式如何解耦?

在Python中,可以通过以下步骤实现观察者模式:

立即学习“Python免费学习笔记(深入)”;

  1. 定义观察者接口 (Observer):定义一个包含 update 方法的抽象类或接口。所有具体的观察者类都必须实现这个接口。

    Python中如何实现观察者模式?观察者模式如何解耦?
  2. 定义具体观察者类 (ConcreteObserver):实现观察者接口,并在 update 方法中定义接收到主题通知后要执行的操作。

  3. 定义主题接口 (Subject):定义一个包含添加、删除和通知观察者方法的抽象类或接口。

    macOS UI 自动化技能包 —— 用 Python 控制你的 Mac
    macOS UI 自动化技能包 —— 用 Python 控制你的 Mac

    让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限

    下载
  4. 定义具体主题类 (ConcreteSubject):实现主题接口,维护一个观察者列表,并在状态改变时遍历列表,调用每个观察者的 update 方法。

  5. 客户端代码:创建主题对象和观察者对象,并将观察者对象注册到主题对象中。当主题对象的状态发生改变时,客户端代码不需要直接操作观察者对象,而是由主题对象自动通知所有观察者对象。

from abc import ABC, abstractmethod

# 观察者接口
class Observer(ABC):
    @abstractmethod
    def update(self, subject):
        pass

# 具体观察者
class ConcreteObserverA(Observer):
    def update(self, subject):
        print(f"ConcreteObserverA: Subject's state is {subject.state}")

class ConcreteObserverB(Observer):
    def update(self, subject):
        print(f"ConcreteObserverB: Subject's state is {subject.state}")

# 主题接口
class Subject(ABC):
    @abstractmethod
    def attach(self, observer):
        pass

    @abstractmethod
    def detach(self, observer):
        pass

    @abstractmethod
    def notify(self):
        pass

# 具体主题
class ConcreteSubject(Subject):
    def __init__(self):
        self._observers = []
        self._state = None # 初始状态设为None

    def attach(self, observer):
        self._observers.append(observer)

    def detach(self, observer):
        self._observers.remove(observer)

    def notify(self):
        for observer in self._observers:
            observer.update(self)

    @property
    def state(self):
        return self._state

    @state.setter
    def state(self, state):
        self._state = state
        self.notify()

# 客户端代码
if __name__ == "__main__":
    subject = ConcreteSubject()

    observer_a = ConcreteObserverA()
    subject.attach(observer_a)

    observer_b = ConcreteObserverB()
    subject.attach(observer_b)

    subject.state = "State 1"
    subject.state = "State 2"

    subject.detach(observer_a)

    subject.state = "State 3"

观察者模式有哪些常见的应用场景?

观察者模式在事件处理系统、GUI 框架、消息队列、模型-视图-控制器(MVC)架构等场景中非常常见。例如,在GUI框架中,按钮点击事件可以被视为主题,而监听按钮点击事件的函数或对象可以被视为观察者。当按钮被点击时,主题(按钮)会通知所有注册的观察者(监听函数或对象),从而触发相应的操作。再比如,在股票交易系统中,股票价格的变动可以被视为主题,而关注该股票的投资者可以被视为观察者。当股票价格发生变动时,系统会通知所有关注该股票的投资者,以便他们及时做出决策。

如何避免观察者模式中的循环依赖?

循环依赖是指观察者和主题之间相互依赖,导致系统陷入无限循环。例如,观察者A监听主题B,而主题B又监听观察者A。当主题B发生改变时,会通知观察者A,而观察者A在接收到通知后又会改变主题B的状态,从而导致主题B再次通知观察者A,形成循环。

避免循环依赖的方法包括:

  • 使用弱引用:使用弱引用可以防止观察者对象阻止主题对象被垃圾回收。
  • 引入中间层:引入一个中间层来协调观察者和主题之间的交互。
  • 限制通知范围:只通知必要的观察者,避免不必要的通知。
  • 事件过滤:观察者只处理特定类型的事件,忽略其他事件。

观察者模式与发布/订阅模式有什么区别?

虽然观察者模式和发布/订阅模式都用于实现一对多的依赖关系,但它们之间存在一些关键区别。

  • 中介者:观察者模式中,主题直接维护观察者列表并通知它们。而在发布/订阅模式中,发布者和订阅者之间通过一个消息代理(Message Broker)进行通信。发布者将消息发布到消息代理,而订阅者从消息代理订阅消息。
  • 耦合度:观察者模式中,主题需要知道所有观察者的具体类型。而在发布/订阅模式中,发布者和订阅者之间是解耦的,发布者不需要知道任何订阅者的信息。
  • 灵活性:发布/订阅模式比观察者模式更灵活,因为它允许发布者和订阅者在不同的时间点进行交互,并且支持更复杂的订阅规则。

选择使用哪种模式取决于具体的应用场景。如果需要实现简单的、同步的一对多依赖关系,并且主题和观察者之间的耦合度可以接受,那么观察者模式是一个不错的选择。如果需要实现更复杂的、异步的、解耦的一对多依赖关系,那么发布/订阅模式可能更适合。

热门AI工具

更多
DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

Flowith
Flowith Hot

Flowith是一款基于画布和智能体工作流的 AI 协作工作空间。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

相关专题

更多
硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

3208

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

5249

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

3869

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

486

2026.01.19

Docker Desktop怎么设置端口映射
Docker Desktop怎么设置端口映射

本专题聚焦Docker Desktop容器端口映射与访问配置,整理从创建容器、设置端口绑定到验证本地服务访问的操作流程。针对端口被占用、映射配置错误、容器服务无法访问等情况,也提供相应的检查方向,方便用户完成端口配置。

0

2026.11.03

Docker Desktop镜像构建教程
Docker Desktop镜像构建教程

想使用Docker Desktop将本地项目构建成Docker镜像?本专题围绕镜像构建的实际操作展开,介绍Dockerfile编写、构建命令使用、镜像标签设置和构建日志查看等内容,同时整理镜像无法生成、依赖安装失败及构建缓存异常等问题的排查思路。

0

2026.11.03

Docker Desktop容器创建指南
Docker Desktop容器创建指南

本专题聚焦Docker Desktop容器创建与运行配置,介绍通过本地镜像或远程镜像创建容器的方法,以及容器启动、终端访问、日志查看和基础管理等操作。针对端口冲突、参数配置不当、容器无法启动等情况,也整理了相应的排查方向。

0

2026.11.03

Tailwind CSS 如何制作导航栏和卡片
Tailwind CSS 如何制作导航栏和卡片

用 Tailwind CSS 制作导航栏和卡片,可先搭建语义化结构,再组合 Flex、Grid、间距、圆角与阴影类。这里整理横向导航、移动端菜单、卡片网格及悬停效果的相关文章,帮助你把常见页面组件做得清晰且适配不同屏幕。

20

2026.11.03

Tailwind CSS 响应式布局怎么写
Tailwind CSS 响应式布局怎么写

Tailwind CSS 响应式布局通常从移动端样式写起,再用 sm、md、lg 等前缀调整不同屏幕宽度下的网格、间距和导航。本专题整理断点配置、Grid 与 Flex 自适应布局及常见溢出问题,帮助你逐步完成多设备适配。

0

2026.11.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn