Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
什么是观察者模式?观察者的实现_创想鸟

什么是观察者模式?观察者的实现

观察者模式是一种一对多的依赖关系,当主题状态改变时,所有观察者自动收到通知并更新。它通过抽象接口实现主题与观察者的解耦,提升系统可扩展性与维护性,广泛应用于事件驱动系统如GUI、MVC、消息队列等。实现时需注意通知风暴、内存泄漏和调试复杂性等陷阱。

什么是观察者模式?观察者的实现

观察者模式,在我看来,它本质上是一种“一对多”的对象依赖关系。简单来说,当一个对象(我们称之为“主题”或“发布者”)的状态发生变化时,所有依赖于它的对象(“观察者”或“订阅者”)都会自动收到通知并更新。这就像你订阅了一份报纸,当报社出版了新一期(状态变化),你作为订阅者就会收到它。它提供了一种机制,让对象之间能够松散地通信,而无需彼此紧密耦合。

解决方案

观察者模式的核心在于解耦。它让主题对象不再需要知道具体观察者的类型,也不需要知道它们是如何更新的。主题只维护一个观察者列表,并在自身状态改变时遍历这个列表,调用每个观察者的通用更新方法。

这个模式通常包含几个关键角色:

主题(Subject / Publisher):它是被观察的对象。它维护一个观察者列表,提供注册(

attach

)和注销(

detach

)观察者的方法,并在自身状态改变时,通知所有已注册的观察者。观察者(Observer / Subscriber):它定义了一个更新接口,当主题状态发生变化时,它会收到通知并执行相应的更新操作。具体主题(ConcreteSubject):实现主题接口,存储感兴趣的状态,并在状态改变时通知观察者。具体观察者(ConcreteObserver):实现观察者接口,存储对具体主题的引用(可选,取决于拉取或推送模型),并实现其更新逻辑以响应主题的通知。

整个流程大致是这样:观察者先向感兴趣的主题注册自己。当主题的某个关键状态发生变化时,它会遍历内部的观察者列表,并逐一调用每个观察者的更新方法,把变化信息传递过去。观察者收到信息后,根据自身逻辑进行处理。

为什么我们需要观察者模式?它的核心价值在哪里?

我个人觉得,观察者模式最核心的价值就是“解耦”。在软件设计中,我们总是在追求低耦合、高内聚。如果一个对象的改变直接导致另一个对象也必须跟着改变,并且这种改变是直接通过硬编码的调用实现的,那么当系统变得复杂时,维护起来简直是噩梦。

观察者模式提供了一个优雅的解决方案:

降低耦合度:主题和观察者之间不再直接依赖具体的实现,它们只通过抽象接口进行交互。这意味着你可以随意增加新的观察者类型,而无需修改主题的代码。反过来也一样,主题的内部实现变化,只要不影响其通知接口,观察者也无需修改。这对于大型、迭代频繁的项目来说,简直是救命稻草。增强可扩展性:当需要增加新的功能来响应某个事件时,你只需要创建一个新的观察者并注册到主题上即可,完全不会影响到现有的代码。这种开放/封闭原则(对扩展开放,对修改封闭)在这里体现得淋漓尽致。构建事件驱动系统:许多现代应用,特别是用户界面(GUI)框架、消息队列、响应式编程,都大量使用了观察者模式的思想。它使得系统能够以事件为中心进行设计,当特定事件发生时,相关的组件能够自动响应。在我做过的几个项目中,UI组件的数据绑定就是典型的观察者模式应用,模型层数据一变,视图层立马更新,效率高且错误少。

它不仅仅是提供了一种通知机制,更是一种管理复杂依赖关系、提升系统柔韧性的设计哲学。

歌者PPT 歌者PPT

歌者PPT,AI 写 PPT 永久免费

歌者PPT 197 查看详情 歌者PPT

如何在实际代码中实现观察者模式?一个简单的Python示例

要实现观察者模式,我们可以从定义抽象基类或接口开始,然后具体实现它们。这里我用Python来演示一个简单的“气象站”例子,气象站是主题,手机显示和网页仪表盘是观察者。

# 抽象主题 (Subject)class Subject:    def __init__(self):        self._observers = [] # 存储观察者的列表    def attach(self, observer):        """添加一个观察者"""        if observer not in self._observers:            self._observers.append(observer)            print(f"Observer {observer.__class__.__name__} attached.")    def detach(self, observer):        """移除一个观察者"""        try:            self._observers.remove(observer)            print(f"Observer {observer.__class__.__name__} detached.")        except ValueError:            print(f"Observer {observer.__class__.__name__} not found.")    def notify(self, message):        """通知所有观察者"""        print("nNotifying observers...")        for observer in self._observers:            observer.update(message)# 抽象观察者 (Observer)class Observer:    def update(self, message):        """接收主题通知并更新"""        raise NotImplementedError("Subclasses must implement update method")# 具体主题 (ConcreteSubject)class WeatherStation(Subject):    def __init__(self, location):        super().__init__()        self._location = location        self._temperature = None        print(f"Weather Station at {self._location} created.")    def set_temperature(self, temp):        """设置温度,并通知观察者"""        if self._temperature != temp: # 只有温度变化才通知            print(f"n--- Weather Station at {self._location}: Temperature changing from {self._temperature} to {temp}°C ---")            self._temperature = temp            self.notify(f"New temperature in {self._location}: {self._temperature}°C")        else:            print(f"nWeather Station at {self._location}: Temperature is still {temp}°C, no change.")    def get_temperature(self):        return self._temperature# 具体观察者 (ConcreteObserver)class PhoneDisplay(Observer):    def __init__(self, name):        self._name = name        print(f"Phone Display '{self._name}' created.")    def update(self, message):        print(f"[{self._name} Phone Display]: Received update - {message}")class WebDashboard(Observer):    def __init__(self, name):        self._name = name        print(f"Web Dashboard '{self._name}' created.")    def update(self, message):        print(f"[{self._name} Web Dashboard]: Displaying - {message}")# 实际使用if __name__ == "__main__":    station = WeatherStation("New York")    phone1 = PhoneDisplay("My iPhone")    dashboard = WebDashboard("Admin Panel")    phone2 = PhoneDisplay("Family Tablet")    # 注册观察者    station.attach(phone1)    station.attach(dashboard)    station.attach(phone2)    # 温度变化,通知所有观察者    station.set_temperature(25)    station.set_temperature(25) # 再次设置相同温度,不应通知    # 移除一个观察者    station.detach(phone1)    # 再次变化,看看谁还会收到通知    station.set_temperature(28)    # 尝试移除一个不存在的观察者    station.detach(PhoneDisplay("Non Existent"))

这个例子展示了“推送”模型,即主题在通知时直接将数据(

message

)推送给观察者。另一种是“拉取”模型,主题只通知观察者“有变化”,然后观察者主动向主题请求所需的数据。具体选择哪种模型,取决于你的应用场景和数据量。另外,在多线程环境中,对

_observers

列表的并发访问需要考虑加锁,避免竞态条件。

观察者模式的常见应用场景与潜在陷阱

观察者模式在软件开发中非常普遍,它几乎无处不在,只是我们可能没有意识到它就是观察者模式的变体。

常见应用场景:

图形用户界面(GUI)事件处理:这是最经典的例子。按钮被点击、文本框内容改变、窗口大小调整,这些都是事件。UI组件(主题)会通知监听器(观察者)这些事件的发生。模型-视图-控制器(MVC)架构:在MVC中,模型(Model)通常扮演主题的角色,当模型的数据发生变化时,它会通知视图(View)和控制器(Controller)进行更新,保持数据的一致性。消息队列/发布-订阅系统(Pub/Sub):Kafka、RabbitMQ等消息中间件的核心机制就是发布-订阅模式,这本质上是观察者模式在分布式系统中的体现。发布者发布消息,订阅者接收消息。响应式编程:像RxJava、RxJS这样的框架,其核心思想就是数据流和变化传播,消费者(观察者)订阅数据流(主题)并对其中产生的事件做出响应。RSS订阅:你订阅一个网站的RSS源,当网站发布新文章时,你的阅读器就会收到通知。

潜在陷阱:

通知风暴(Notification Storms):如果一个主题有大量的观察者,并且它的状态变化非常频繁,那么每次变化都可能导致大量的通知和更新操作,这会严重影响系统性能。我见过一个系统,因为没有节流机制,导致一个小的状态变化引发了雪崩式的UI更新。通知顺序不确定性:基本的观察者模式不保证通知的顺序。如果观察者之间存在依赖关系,即某个观察者的更新依赖于另一个观察者已经完成更新,那么这种不确定性可能会导致难以调试的错误。内存泄漏:这是一个非常实际的问题。如果观察者注册到主题后,没有在适当的时机(比如对象销毁时)注销自己,那么主题会一直持有对这些观察者的引用,即使观察者本身已经不再需要,也无法被垃圾回收,从而导致内存泄漏。调试复杂性:由于主题和观察者之间的松散耦合,以及事件驱动的异步特性,当出现问题时,追踪代码的执行流可能会变得相当困难,因为它不像传统的顺序调用那样直观。过度设计:不是所有的一对多关系都需要观察者模式。如果关系简单且稳定,直接调用可能更清晰、更高效。引入观察者模式会增加代码的复杂性,如果收益不明显,那就不值得。

所以,虽然观察者模式非常强大和有用,但在实际应用中,我们需要权衡其优点和可能带来的复杂性,并注意规避上述陷阱。

以上就是什么是观察者模式?观察者的实现的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/230203.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
详解Laravel使用多数据库的方法(附代码示例)
上一篇 2025年11月3日 20:46:49
任天堂游戏辅助道具amiibo新品预购 玩家惊呼价格太高
下一篇 2025年11月3日 20:46:50

相关推荐

  • Java多线程并发控制:告别线程优先级,拥抱锁机制

    本文深入探讨了在Java多线程环境中如何有效解决并发操作中断问题,特别是当多个线程尝试同时执行非原子性操作(如打印)时。文章指出,单纯依赖线程优先级并不可靠,并详细介绍了使用synchronized关键字配合共享锁对象实现互斥访问的关键技术,确保关键代码块的原子性执行,从而避免数据混乱和逻辑错误。 …

    2026年9月22日
    700
  • 使用空值合并运算符为数组元素设置默认值

    本文将介绍如何使用 PHP 的空值合并运算符 (??) 为数组元素设置默认值,尤其是在处理用户输入时。 通过该运算符,可以在变量值为 null 或不存在时,提供一个备选值,从而简化代码并提高可读性。我们将通过一个实际的 Laravel 邮件发送示例,演示如何在请求参数中缺失主题时,设置默认主题。 空…

    2026年9月22日
    600
  • VSCode精简配置Git:中文提交记录、分支可视化、冲突解决

    首先解决中文乱码需配置Git和VSCode编码为UTF-8,其次通过GitLens或Git Graph实现分支可视化,最后利用VSCode内置的冲突解决工具高效处理合并冲突,全面提升Git使用体验。 在VSCode里用Git,我总觉得能再顺手点。特别是处理中文提交信息、想直观看看分支图,或者面对恼人…

    2026年9月22日
    500
  • 如何用AdobePremierePro制作AI视频?快速上手AI视频剪辑的完整教程

    如何用AdobePremierePro制作AI视频?快速上手AI视频剪辑的完整教程如何用AdobePremierePro制作AI视频?快速上手AI视频剪辑的完整教程如何用AdobePremierePro制作AI视频?快速上手AI视频剪辑的完整教程如何用AdobePremierePro制作AI视频?快速上手AI视频剪辑的完整教程

    答案:在Premiere Pro中制作AI视频需整合第三方AI工具生成的素材并进行精细化剪辑。首先明确主题,利用Midjourney、RunwayML、ElevenLabs等工具生成图像、视频和音频;随后导入PR并分类组织,通过粗剪与同步构建叙事框架;接着运用Lumetri Color统一色调,基本…

    2026年9月22日 用户投稿
    1200
  • 不懂技术也能做!蝴蝶号入口搭建与数据增长实战指南

    是的,不懂技术也能搭建“蝴蝶号入口”并实现数据增长。其核心在于明确目标与受众、选择合适的无代码工具、打造有价值的内容、积极推广、关注数据分析并持续优化。具体步骤为:1. 明确用户行为路径和转化目标;2. 选用linktree、notion、wix等无代码工具搭建入口;3. 输出简洁有吸引力的内容;4…

    2026年9月22日
    400
  • iPhone 15运动和健康设置如何操作

    运动目标自定义 进入“健康”App,选择“运动”板块。在这里,你可以根据自身情况设定每日运动目标,例如步数、行走距离或燃烧的卡路里。比如将每日步数目标设为10000步,一旦达成,系统会自动弹出祝贺提示,给予正向激励。此外,在“数据来源”中可绑定Apple Watch等设备,提升数据采集的准确性与全面…

    2026年9月22日
    000
  • 美团外卖新人优惠券领取入口_美团新人专享优惠券获取方法

    新用户可通过扫描官方二维码、完成App内新手任务、第三方平台链接及参与限时抢券活动领取美团外卖无门槛红包或大额优惠券,享受首单减免。 如果您是美团外卖的新用户,想要在下单时享受优惠,可以通过多种方式领取新人专享优惠券。这些优惠券通常为无门槛红包或大额满减券,能有效降低首次订餐成本。 本文运行环境:i…

    2026年9月22日
    000
  • Reinstalling Alpine Linux on a Lighthouse Instance

    Start by creating an instance with Debian or your preferred operating system. Log into the instance. Download the Arch Linux ISO for booting. Although…

    2026年9月22日
    000
  • VSCode调试FPGA工程的技巧(结合Vivado,快速定位问题)

    vscode在fpga开发中并非替代vivado,而是作为高效辅助工具提升开发效率。1. 在代码编写方面,vscode提供 superior 的语法高亮、自动补全和代码管理功能,显著优化verilog、systemverilog和tcl脚本的编写体验,并通过git实现无缝版本控制;2. 在仿真与自动…

    2026年9月22日
    1200
  • 小米双11正式开启!覆盖全品类 单品最高可省4000元

    10月13日,小米官方宣布“小米双11”大促活动全面启动。此次活动涵盖小米全品类产品,优惠力度空前,部分单品最高直降4000元。 在手机产品线中,小米最新旗舰大折叠屏MIX Fold 4迎来大幅让利,最高降价1000元,最终到手价为7999元。搭载顶级影像系统的旗舰机型小米15 Ultra也下调50…

    2026年9月22日
    400
  • Apache Pulsar 主题分区创建与管理指南

    本文深入探讨Apache Pulsar主题分区的创建与管理。Pulsar主题分区是实现高吞吐量和可伸缩性的关键,但必须在主题创建时进行配置。文章详细介绍了两种主要的分区主题创建方法:通过Broker配置实现自动分区,以及利用Pulsar Admin API进行显式创建,并强调了分区主题一旦创建后不可…

    2026年9月22日
    100
  • iPhone情侣模式如何自定义表情包?制作专属情侣表情的详细步骤

    iPhone情侣模式下可自定义表情包,通过Memoji或第三方App实现。首先可用“信息”应用创建Memoji,自定义外貌特征并录制视频发送;其次在App Store下载表情包制作App,上传合照或个人照,添加文字、贴纸、边框等元素,制成情侣专属静态或GIF表情包,支持导出为iMessage贴纸;还…

    2026年9月22日
    000
  • 如何查看Linux文件系统类型 df -T与lsblk -f命令对比

    如何查看Linux文件系统类型 df -T与lsblk -f命令对比如何查看Linux文件系统类型 df -T与lsblk -f命令对比如何查看Linux文件系统类型 df -T与lsblk -f命令对比如何查看Linux文件系统类型 df -T与lsblk -f命令对比

    在linux中查看文件系统类型时,df -t 适合查看已挂载分区的文件系统,而 lsblk -f 可查看所有块设备信息。1. df -t 显示已挂载的文件系统类型、磁盘使用情况及挂载点,适用于快速了解当前挂载目录所用文件系统;2. lsblk -f 列出包括未挂载设备的详细信息,如 uuid、lab…

    2026年9月22日 用户投稿
    300
  • 用AI打造沉浸式蝴蝶号无人直播间操作实录

    用AI打造沉浸式蝴蝶号无人直播间操作实录用AI打造沉浸式蝴蝶号无人直播间操作实录用AI打造沉浸式蝴蝶号无人直播间操作实录用AI打造沉浸式蝴蝶号无人直播间操作实录

    用ai做蝴蝶号无人直播间确实可以“无人”,但关键在于流程跑通与细节做好。具体步骤包括:一、准备阶段要配齐账号、素材和工具,明确账号定位,建立丰富素材库,选对ai工具并从垂直领域测试;二、设计脚本时需预设规则匹配,整理常见问题与回答表格导入系统;三、实操上设置定时推流、语音讲解、弹幕监控和自动下播等流…

    2026年9月22日 用户投稿
    1200
  • PowerBI的AI混合工具怎么用?快速创建数据报表的详细操作方法

    PowerBI的AI混合工具通过Q&A、关键影响因素、异常检测和智能叙事等功能,降低数据分析门槛,加速从数据到决策的全过程。它让非技术人员用自然语言提问获取图表,自动识别数据异常与驱动因素,并生成文字解读,大幅提升分析效率。但需以高质量数据和合理建模为基础,结合业务逻辑验证结果,避免“垃圾进…

    2026年9月22日
    600
  • VSCode安装Go语言插件(图文详解,新手避坑指南)

    首先安装Go SDK并配置环境变量,再安装VSCode及Go插件,关键步骤是通过Go: Install/Update Tools命令安装gopls、dlv等核心工具链,确保代码补全、调试等功能正常;若遇问题,需检查Go版本、GOPROXY代理、权限及网络,结合输出面板错误信息定位解决。 配置VSCo…

    2026年9月22日
    400
  • Sublime用于MySQL分库分表设计逻辑_适合大型系统水平扩展需求

    Sublime用于MySQL分库分表设计逻辑_适合大型系统水平扩展需求Sublime用于MySQL分库分表设计逻辑_适合大型系统水平扩展需求Sublime用于MySQL分库分表设计逻辑_适合大型系统水平扩展需求Sublime用于MySQL分库分表设计逻辑_适合大型系统水平扩展需求

    分库分表通过拆分数据提升数据库性能与扩展性,常见策略包括垂直分表、水平分表和分库;sublime 可辅助设计逻辑。1. 垂直分表按字段拆分,降低单表复杂度;2. 水平分表按行拆分,提升查询效率;3. 分库减少单节点压力,增强系统吞吐能力。使用 sublime 可高效编写 sql 脚本、注释分片规则、…

    2026年9月22日 用户投稿
    500
  • 笔记—Linux安装OpenCV及VSCode的配置编译

    笔记—Linux安装OpenCV及VSCode的配置编译笔记—Linux安装OpenCV及VSCode的配置编译笔记—Linux安装OpenCV及VSCode的配置编译笔记—Linux安装OpenCV及VSCode的配置编译

    在学习新技能的过程中,我选择了在linux系统上进行操作,这对于从未接触过linux的人来说是一个绝佳的学习机会。这篇文章记录了我在linux上安装opencv的过程。 我选择的Linux发行版是Ubuntu 20.04.3,并将其安装在Virtual Box虚拟机中。Ubuntu的相关资料丰富,选…

    2026年9月22日 用户投稿
    100
  • PHP如何执行存储过程_PHP调用mysql存储过程的详细步骤

    PHP调用MySQL存储过程主要通过PDO实现,需先启用PDO扩展并建立数据库连接。1. 使用new PDO()连接MySQL;2. 调用无参存储过程如CALL get_users(),执行后获取结果集;3. 对带输入参数的存储过程使用bindParam绑定参数;4. 处理OUT参数时通过用户变量(…

    2026年9月22日
    000
  • 使用Sublime管理MySQL数据库结构_高效编辑表结构与字段定义脚本

    使用Sublime管理MySQL数据库结构_高效编辑表结构与字段定义脚本使用Sublime管理MySQL数据库结构_高效编辑表结构与字段定义脚本使用Sublime管理MySQL数据库结构_高效编辑表结构与字段定义脚本使用Sublime管理MySQL数据库结构_高效编辑表结构与字段定义脚本

    用 sublime text 管理 mysql 数据库结构脚本高效且灵活。1. 适合习惯文本编辑、需自定义流程的开发者;2. 启动快、资源占用低,支持多光标、正则替换,插件丰富,易配合 git;3. 建议每张表单独文件、按模块分目录、主脚本汇总建表语句,索引外键单独文件;4. 推荐插件有 sqlto…

    2026年9月22日 用户投稿
    000

发表回复

登录后才能评论
关注微信