当前位置: 首页 > article >正文

漫谈设计模式 [15]:观察者模式

引导性开场

菜鸟:老鸟,我最近在做一个项目,需要很多部分同步更新,但每次修改一个地方都要改好几个其他地方,感觉很麻烦,有没有什么更好的方法?

老鸟:听起来你遇到了典型的同步更新问题。有没有听说过观察者模式?

菜鸟:好像听过,但不太清楚具体是怎么回事。

老鸟:没关系,我们可以从头开始聊起。其实,观察者模式就是为了解决你这种同步更新的需求。

渐进式介绍概念

老鸟:我们先从生活中的例子聊起吧。假设你是个新闻记者,每当有重大新闻发生时,你需要通知各种媒体平台,比如电视、电台、报纸等。每次你都得一个一个通知,感觉很麻烦吧?

菜鸟:是啊,如果能一次通知所有人就好了。

老鸟:没错,这就是观察者模式的核心思想。你可以把自己看作"被观察者"(Subject),而那些需要通知的媒体平台看作"观察者"(Observer)。当有新闻发生时,你只需要告诉所有观察者,他们自己会去更新。

Python代码示例,逐步展开

菜鸟:听起来不错,有没有具体的代码例子?

老鸟:当然有,我们从一个简单的例子开始。

class Subject:
    def __init__(self):
        self._observers = []

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

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

class Observer:
    def update(self, message):
        pass

class Newspaper(Observer):
    def update(self, message):
        print(f"Newspaper received: {message}")

class TV(Observer):
    def update(self, message):
        print(f"TV received: {message}")

# 使用示例
news_subject = Subject()
newspaper = Newspaper()
tv = TV()

news_subject.attach(newspaper)
news_subject.attach(tv)

news_subject.notify("Breaking News!")

菜鸟:原来是这样,通过 attach 方法把观察者加进去,然后通过 notify 方法通知所有观察者。

老鸟:没错,这样每当有消息发布时,所有的观察者都会自动收到通知。

问题与反思

菜鸟:这个方法确实比我原来的手动通知要好,但如果有很多类型的观察者,是不是会有很多类?

老鸟:确实会有很多类,但这正是面向对象编程的优势,你可以通过继承和多态来灵活管理这些类。你觉得手动通知和观察者模式相比,哪个更容易维护?

菜鸟:观察者模式更容易维护,而且扩展新观察者也很方便。

老鸟:对了,你还可以考虑使用更复杂的实现,比如添加移除观察者的方法,或者使用更复杂的通知机制。

优势与适用场景

菜鸟:这种模式的优势除了易于维护和扩展,还有什么?

老鸟:观察者模式的另一个优势是解耦。被观察者和观察者可以独立变化,不用彼此依赖。适用的场景包括GUI事件处理、订阅-发布系统等。

常见误区与优化建议

菜鸟:那有没有什么常见的误区需要注意?

老鸟:有的,比如容易导致过多的依赖关系,观察者模式本质上是解耦的,但如果不小心设计,可能会产生复杂的依赖关系。另外,要注意性能问题,特别是当观察者数量很多时。

总结与延伸阅读

老鸟:今天我们聊了观察者模式,主要解决了同步更新的问题,核心是解耦和易于扩展。你可以进一步阅读《设计模式:可复用面向对象软件的基础》这本书,里面有更详细的介绍。

菜鸟:谢谢老鸟,我觉得这个模式很有用,我打算继续学习其他设计模式。

老鸟:好的,下一步你可以学习策略模式或工厂模式,这些模式都会在不同场景下帮到你。

菜鸟:好的,我会去看看。谢谢你!

老鸟:不客气,有问题随时来问我。


http://www.kler.cn/news/295031.html

相关文章:

  • 9. 相机控件OrbitControls
  • C++11线程池、多线程编程(附源码)
  • 信息熵|atttion矩阵的注意力熵
  • 设计并用Java实现一个简易的规则引擎
  • Python | Leetcode Python题解之第392题判断子序列
  • 【leetcode详解】爬楼梯:DP入门典例(附DP通用思路 同类进阶练习)
  • 使用Protocol Buffers传输数据
  • 在vscode中用virtual env的方法
  • git如何灵活切换本地账号对应远程github的两个账号
  • 代码随想录:279. 完全平方数
  • 如何在Selenium中使用Chrome进行网络限速
  • ComfyUI+Krea免费利用AI制作网站萌宠IP,五步搞定制作AI萌宠
  • React 响应事件
  • 【Godot4.3】多边形的斜线填充效果基础实现
  • 在Ubuntu 20.04上安装Nginx的方法
  • 懒人笔记-opencv4.8.0篇
  • 【详解 Java 注解】
  • 一些数学经验总结——关于将原一元二次函数增加一些限制条件后最优结果的对比(主要针对公平关切相关的建模)
  • 分数阶微积分MATLAB计算
  • 将你的github仓库设置为web代理
  • Java零基础-如何在分布式系统中进行日志管理?
  • 【鸿蒙】HarmonyOS NEXT星河入门到实战1-开发环境准备
  • Vulnhub:Dr4g0n b4ll 1
  • Qt/C++开源项目 TCP客户端调试助手(源码分享+发布链接下载)
  • <class ‘pyspark.sql.dataframe.DataFrame‘>
  • Eureka原理与实践:构建高可用微服务架构的基石
  • MCU5.51单片机的最小系统
  • IDEA git提交时如何忽略某个文件或文件夹
  • 任务执行拓扑排序(华为od机考题)
  • Elasticsearch - SpringBoot 索引与文档相关demo