8.观察者模式:思考与解读
原文地址:观察者模式:思考与解读 更多内容请关注:7.深入思考与解读设计模式
引言
在开发软件时,系统的某些状态可能会发生变化,而你希望这些变化能够自动通知到依赖它们的其他模块。你是否曾经遇到过,系统中某个对象发生了变化,但你不想让其他对象频繁地去询问这个变化,或者你不希望每次变化时都手动通知这些对象?
如果可以有一种方式,当对象的状态发生变化时,所有依赖该对象的其他对象都能自动得到通知并做出响应,这样的设计是否会让你的系统更加松耦合且易于维护?
这正是观察者模式的目的。观察者模式通过定义一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会收到通知。你是否觉得,这样的模式能够减少系统中对象之间的耦合,使得系统更加灵活?
在这篇文章中,我们将通过一系列问题,逐步引导你理解观察者模式的核心思想、应用场景以及如何实现它。
什么是观察者模式?
问题1:在软件设计中,如果有一个对象发生了变化,你通常如何通知其他依赖它的对象?
假设你有一个系统,其中有一个对象的状态变化会影响到其他多个对象。你是如何让这些依赖对象知道这个变化的?是否有一种方法,让这些对象在不询问的情况下,自动获取到最新的状态?
问题2:你是否曾经使用过“事件监听器”或“回调”机制?这些方法是否能够灵活地处理对象之间的依赖关系?
事件监听器和回调机制在某些场景下是非常有用的,但它们通常会带来强耦合。而观察者模式则能够更灵活地处理一对多的依赖关系。你是否想过,是否有一种设计模式能够解决这种问题?
观察者模式正是解决这个问题的一种有效设计模式,它通过“观察者”来自动通知依赖对象,而不需要依赖对象主动查询。
观察者模式的核心概念
问题3:观察者模式通常由哪些角色组成?每个角色的职责是什么?
观察者模式包含以下几个核心角色:
-
主题(Subject):被观察的对象,通常包含一个状态,当它的状态发生变化时,会通知所有注册的观察者。
-
观察者(Observer):依赖于主题的对象,当主题发生变化时,观察者会得到通知并进行相应的处理。
-
具体主题(ConcreteSubject):实现了主题接口,维护观察者列表,并在状态变化时通知它们。
-
具体观察者(ConcreteObserver):实现了观察者接口,响应主题的变化。
你能理解这些角色是如何相互协作,确保在主题变化时,观察者能够自动得到通知吗?
问题4:在观察者模式中,主题与观察者是如何解耦的?它们是如何通过某种机制进行通信的?
观察者模式的关键是,主题不需要知道具体有哪些观察者,它只需要维护一个观察者的列表,并在状态变化时通知所有的观察者。你能理解,这样的设计是如何让系统中的各个部分更加解耦的?
观察者模式的实现
让我们通过一个简单的例子来理解观察者模式的实现。假设你正在开发一个天气预报系统,系统中有多个展示天气信息的应用(例如,手机应用、网页应用等),当天气数据发生变化时,所有应用都应该被通知并更新显示的内容。
步骤1:定义观察者接口
from abc import ABC, abstractmethod# 观察者接口 class Observer(ABC):@abstractmethoddef update(self, temperature: float, humidity: float):pass
问题5:观察者接口(Observer)定义了哪些方法?为什么需要一个统一的接口来保证所有观察者的行为一致?
观察者接口定义了一个update()方法,所有观察者都必须实现这个方法。你是否理解,为什么这种方式能够确保所有观察者在状态变化时都能得到统一的通知,并进行相应的处理?
步骤2:定义主题接口
class Subject(ABC):@abstractmethoddef register_observer(self, observer: Observer):pass@abstractmethoddef remove_observer(self, observer: Observer):pass@abstractmethoddef notify_observers(self):pass
问题6:主题接口(Subject)需要提供哪些方法来管理观察者?它为什么需要register_observer()、remove_observer()和notify_observers()方法?
主题接口通过register_observer()、remove_observer()和notify_observers()来管理观察者列表。你是否理解,为什么这些方法是观察者模式的核心?它们如何帮助主题管理观察者,并在状态变化时通知所有观察者?
步骤3:定义具体主题类
class WeatherStation(Subject):def __init__(self):self._observers = []self._temperature = 0.0self._humidity = 0.0def register_observer(self, observer: Observer):self._observers.append(observer)def remove_observer(self, observer: Observer):self._observers.remove(observer)def notify_observers(self):for observer in self._observers:observer.update(self._temperature, self._humidity)def set_weather_data(self, temperature: float, humidity: float):self._temperature = temperatureself._humidity = humidityself.notify_observers() # 当天气数据变化时通知所有观察者
问题7:具体主题类(WeatherStation)如何管理观察者,并在状态变化时通知它们?
WeatherStation类维护一个观察者列表,并通过notify_observers()方法通知所有观察者。你是否能理解,为什么我们通过set_weather_data()方法来触发状态变化,并通知所有的观察者?
步骤4:定义具体观察者类
class PhoneApp(Observer):def update(self, temperature: float, humidity: float):print(f"Phone App: Weather updated! Temperature: {temperature}°C, Humidity: {humidity}%")class WebApp(Observer):def update(self, temperature: float, humidity: float):print(f"Web App: Weather updated! Temperature: {temperature}°C, Humidity: {humidity}%")
问题8:具体观察者类(如PhoneApp、WebApp)是如何响应主题的变化的?它们为什么需要实现update()方法?
具体观察者类实现了update()方法,并在该方法中处理主题状态变化后的逻辑(如更新显示)。你是否理解,为什么观察者需要根据主题的变化来更新自己的状态,而这种更新是自动触发的?
步骤5:客户端代码
def main():weather_station = WeatherStation()phone_app = PhoneApp()web_app = WebApp()weather_station.register_observer(phone_app)weather_station.register_observer(web_app)weather_station.set_weather_data(25.5, 60) # 模拟天气数据变化weather_station.set_weather_data(30.0, 65) # 再次模拟天气数据变化if __name__ == "__main__":main()
问题9:在客户端代码中,如何通过主题对象来注册观察者,并触发通知?当天气数据发生变化时,如何确保所有观察者都能接收到通知?
客户端通过register_observer()方法注册观察者对象,当天气数据变化时,WeatherStation通过调用notify_observers()通知所有注册的观察者。你是否理解,这种机制如何保证了在状态变化时,所有依赖对象(观察者)都能自动响应?
观察者模式的优缺点
问题10:观察者模式的优点是什么?它如何帮助我们解耦系统中的不同模块?
观察者模式通过将主题与观察者解耦,避免了直接依赖关系,使得系统更加灵活和可扩展。你是否理解,这种设计如何帮助你在不修改主题类的情况下,轻松增加新的观察者?同时,观察者也不需要知道主题类的具体实现。
问题11:观察者模式的缺点是什么?它在某些情况下是否会导致性能问题或过度通知?
虽然观察者模式非常灵活,但在某些情况下,当有大量观察者时,可能会导致性能问题。你是否认为,如果观察者数量过多,通知的效率可能成为瓶颈?或者,是否可能存在不必要的通知?
适用场景
问题12:你能想到哪些场景,观察者模式能够发挥作用?
观察者模式适用于以下场景:
-
当多个对象依赖于某个对象的状态变化时。
-
当你需要将事件驱动机制引入系统时。
你能想到其他场景吗?例如,用户界面的事件监听、股票市场的价格更新等,是否也可以使用观察者模式?
问题13:观察者模式是否适用于所有场景?在某些情况下,是否有更合适的设计模式?
观察者模式适用于需要多方监听和响应的场景,但如果对象之间的依赖较少,或者没有动态更新的需求,是否可以使用更简单的设计模式?
接下来,我们将通过具体的代码示例来加深理解观察者模式。
观察者模式深入解读
一、引言
观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某个主题对象。当主题对象的状态发生变化时,所有依赖于它的观察者都会得到通知并自动更新。观察者模式通常用于事件处理系统,比如用户界面、消息通知系统等。
二、简单理解:什么是观察者模式?
1. 什么是观察者模式?
观察者模式的核心思想是:当一个对象的状态发生改变时,所有依赖于它的对象都会自动得到通知并更新。这个模式常用于一种场景:当数据发生变化时,其他对象需要得到变化的通知并作出响应。
通俗地讲,观察者模式就像是你订阅了一家新闻网站,每当该网站发布了新的新闻,你就会收到通知。你不需要主动去检查网站是否有新新闻,而是当新闻发生变化时,系统会自动通知你。
2. 观察者模式的组成部分
观察者模式通常包含以下几个部分:
-
主题(Subject):维护一组观察者,并在状态变化时通知所有观察者。
-
观察者(Observer):定义一个更新接口,供主题在状态发生变化时调用。
-
具体主题(ConcreteSubject):实现主题接口,保存状态,并在状态变化时通知观察者。
-
具体观察者(ConcreteObserver):实现观察者接口,根据主题的状态变化做出响应。
三、用自己的话解释:如何理解观察者模式?
1. 类比实际生活中的场景
假设你是一家杂志的订阅者,每当这本杂志出版新一期时,你都会收到邮件通知。这时候,你是“观察者”,杂志社是“主题”,每当杂志社发布新内容时,它会通知所有订阅的读者。
在编程中,观察者模式通常应用于一对多的关系,当一个对象的状态变化时,其他对象会被通知并自动更新。比如,用户界面中一个输入框的值发生变化时,其他依赖于这个输入框值的组件(如显示结果的标签、搜索框等)会自动更新。
2. 为什么要使用观察者模式?
观察者模式的主要优势在于,它通过松耦合的方式管理对象之间的依赖关系。观察者与主题之间没有直接的连接,主题只知道观察者的接口,不知道具体的实现,这使得系统更加灵活和可扩展。
四、深入理解:观察者模式的实现
接下来,我们通过一个具体的代码示例来实现观察者模式,帮助你更好地理解如何在代码中使用这个模式。
示例:新闻推送系统
假设我们要开发一个新闻推送系统,用户可以订阅不同的新闻类型。当有新的新闻发布时,所有订阅该类型的用户都会收到通知。
1. 定义观察者接口
# 观察者接口:定义更新方法 class Observer:def update(self, message: str):pass
2. 定义主题接口
# 主题接口:定义注册、移除观察者的方法 class Subject:def register_observer(self, observer: Observer):passdef remove_observer(self, observer: Observer):passdef notify_observers(self):pass
3. 定义具体主题类:新闻发布
# 具体主题类:新闻发布
class NewsPublisher(Subject):def __init__(self):self._observers = []self._latest_news = ""def register_observer(self, observer: Observer):self._observers.append(observer)def remove_observer(self, observer: Observer):self._observers.remove(observer)def notify_observers(self):for observer in self._observers:observer.update(self._latest_news)def set_latest_news(self, news: str):self._latest_news = newsself.notify_observers() # 状态变化时通知所有观察者
4. 定义具体观察者类:用户
# 具体观察者类:用户
class User(Observer):def __init__(self, name: str):self._name = namedef update(self, message: str):print(f"{self._name} received news: {message}")
5. 客户端代码:订阅新闻
# 创建新闻发布者实例
news_publisher = NewsPublisher()# 创建用户实例
user1 = User("Alice")
user2 = User("Bob")# 用户订阅新闻
news_publisher.register_observer(user1)
news_publisher.register_observer(user2)# 发布新闻
news_publisher.set_latest_news("Breaking: New python version released!")# 取消某个用户的订阅
news_publisher.remove_observer(user2)# 再次发布新闻
news_publisher.set_latest_news("Update: Python tutorial available!")
代码解析:
-
Observer类:这是观察者接口,定义了update方法,主题会通过这个方法通知观察者更新。 -
Subject类:这是主题接口,定义了register_observer、remove_observer和notify_observers方法,用来管理观察者的注册、移除和通知。 -
NewsPublisher类:这是具体的主题类,继承了Subject,并实现了管理观察者和通知更新的逻辑。当有新的新闻发布时,它会调用notify_observers方法,通知所有注册的观察者。 -
User类:这是具体的观察者类,继承了Observer,当主题状态变化时,通过update方法接收到新新闻的通知。 -
客户端代码:创建新闻发布者和多个用户,用户订阅新闻发布,发布者通知所有订阅的用户更新。
五、解释给别人:如何讲解观察者模式?
1. 用简单的语言解释
观察者模式就像是你订阅了一个新闻频道,每当有新新闻发布时,你都会收到通知。你不需要时刻查看新闻网站,而是当新闻变化时,你会自动收到更新。它让你能跟随某个变化的对象,而不用频繁地查询该对象。
2. 为什么要使用观察者模式?
使用观察者模式的好处是,它让系统的各个组件之间通过接口解耦。主题和观察者之间没有直接的依赖,主题只知道观察者的接口,并且通过通知机制来更新观察者。当有新观察者加入或离开时,主题不需要做太多改动,从而提高了系统的灵活性和扩展性。
六、总结
通过一系列问题的引导,我们逐步理解了观察者模式的核心思想和实现方式。观察者模式通过定义一对多的依赖关系,使得当一个对象的状态发生变化时,所有依赖对象能够自动接收到通知并做出响应。它让系统更加松耦合,灵活且可扩展。
通过以上过程,我们可以得出以下结论:
-
观察者模式 是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某个主题对象。当主题对象的状态发生变化时,所有依赖于它的观察者都会得到通知并自动更新。
-
它的主要优点是解耦、灵活性和扩展性,尤其适用于事件驱动或消息推送的场景。
-
观察者模式的应用非常广泛,例如 GUI 组件、事件处理、推送通知系统等。
观察者模式的优点:
-
松耦合:观察者和主题之间没有直接依赖,便于扩展和维护。
-
扩展性:可以灵活地增加或移除观察者,而不影响主题。
-
易于实现:适合实现一对多的通信关系,尤其在实时更新场景中非常有用。
观察者模式的缺点:
-
可能导致性能问题:如果观察者数量非常多,可能会影响通知效率。
-
依赖复杂:如果观察者和主题之间有太多复杂的依赖,可能会导致系统的理解和维护难度增加。
相关文章:
8.观察者模式:思考与解读
原文地址:观察者模式:思考与解读 更多内容请关注:7.深入思考与解读设计模式 引言 在开发软件时,系统的某些状态可能会发生变化,而你希望这些变化能够自动通知到依赖它们的其他模块。你是否曾经遇到过,系统中某个对象…...
CMake execute_process用法详解
execute_process 是 CMake 中的一个命令,用于在 CMake 配置阶段(即运行 cmake 命令时)执行外部进程。它与 add_custom_command 或 add_custom_target 不同,后者是在构建阶段(如 make 或 ninja)执行命令。ex…...
模型加载常见问题
safetensors_rust.SafetensorError: Error while deserializing header: HeaderTooLarge 问题代码: model AutoModelForVision2Seq.from_pretrained( "/data-nvme/yang/Qwen2.5-VL-32B-Instruct", trust_remote_codeTrue, torch_dtypetorc…...
PyTorch 深度学习实战(37):分布式训练(DP/DDP/Deepspeed)实战
在上一篇文章中,我们探讨了混合精度训练与梯度缩放技术。本文将深入介绍分布式训练的三种主流方法:Data Parallel (DP)、Distributed Data Parallel (DDP) 和 DeepSpeed,帮助您掌握大规模模型训练的关键技术。我们将使用PyTorch在CIFAR-10分类…...
微信小程序通过mqtt控制esp32
目录 1.注册巴法云 2.设备连接mqtt 3.微信小程序 备注 本文esp32用的是MicroPython固件,MQTT服务用的是巴法云。 本文参考巴法云官方教程:https://bemfa.blog.csdn.net/article/details/115282152 1.注册巴法云 注册登陆并新建一个topicÿ…...
1.Vue3 - 创建Vue3工程
目录 一、 基于vue-cli 脚手架二、基于vite 推荐2.1 介绍2.2 创建项目2.3 文件介绍2.3.1 extensions.json2.3.2 脚手架的根目录2.3.3 主要文件 src2.3.3.1 main.js2.3.3.2 App.vue 组件2.3.3.3 conponents 2.3.4 env.d.ts2.3.5 index.html 入口文件2.3.6 package2.3.7 tsconfig…...
AI编写的“黑科技风格、自动刷新”的看板页面
以下的 index.html 、 script.js 和 styles.css 文件,实现一个具有黑科技风格、自动刷新的能源管理系统实时监控看板。 html页面 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name&q…...
11-DevOps-Jenkins Pipeline流水线作业
前面已经完成了,通过在Jenkins中创建自由风格的工程,在界面上的配置,完成了发布、构建的过程。 这种方式的缺点就是如果要在另一台机器上进行同样的配置,需要一项一项去填写,不方便迁移,操作比较麻烦。 解…...
23种设计模式-结构型模式之外观模式(Java版本)
Java 外观模式(Facade Pattern)详解 🧭 什么是外观模式? 外观模式是结构型设计模式之一,为子系统中的一组接口提供一个统一的高层接口,使得子系统更易使用。 就像是酒店前台,帮你处理入住、叫…...
【JavaWeb后端开发03】MySQL入门
文章目录 1. 前言1.1 引言1.2 相关概念 2. MySQL概述2.1 安装2.2 连接2.2.1 介绍2.2.2 企业使用方式(了解) 2.3 数据模型2.3.1 **关系型数据库(RDBMS)**2.3.2 数据模型 3. SQL语句3.1 DDL语句3.1.1 数据库操作3.1.1.1 查询数据库3.1.1.2 创建数据库3.1.1…...
Github 热点项目 Jumpserver开源堡垒机让服务器管理效率翻倍
Jumpserver今日喜提160星,总星飙至2.6万!这个开源堡垒机有三大亮点:① 像哆啦A梦的口袋,支持多云服务器一站式管理;② 安全审计功能超硬核,操作记录随时可回放;③ 网页终端无需装插件࿰…...
第七届传智杯全国IT技能大赛程序设计赛道 国赛(总决赛)—— (B组)题解
1.小苯的木棍切割 【解析】首先我们先对数列排序,找到其中最小的数,那么我们就保证了对于任意一个第i1个的值都会大于第i个的值那么第i2个的值也比第i个大,那么我们第i1次切木棍的时候一定会当第i个的值就变为了0的,第i1减去的应该…...
Netty前置基础知识之BIO、NIO以及AIO理论详细解析和实战案例
前言 Netty是什么? Netty 是一个基于 Java 的 高性能异步事件驱动网络应用框架,主要用于快速开发可维护的协议服务器和客户端。它简化了网络编程的复杂性,特别适合构建需要处理海量并发连接、低延迟和高吞吐量的分布式系统。 1)Netty 是…...
开源身份和访问管理(IAM)解决方案:Keycloak
一、Keycloak介绍 1、什么是 Keycloak? Keycloak 是一个开源的身份和访问管理(Identity and Access Management - IAM)解决方案。它旨在为现代应用程序和服务提供安全保障,简化身份验证和授权过程。Keycloak 提供了集中式的用户…...
深入理解 TCP 协议 | 流量、拥塞及错误控制机制
注:本文为 “TCP 协议” 相关文章合辑。 原文为繁体,注意术语描述差异。 略作重排,如有内容异常,请看原文。 作者在不同的文章中互相引用其不同文章,一并汇总于此。 可从本文右侧目录直达本文主题相关的部分ÿ…...
VSCode远程图形化GDB
VSCode远程图形化GDB 摘要一、安装VSCode1、使用.exe安装包安装VSCode2、VSCode 插件安装3、VSCode建立远程连接 二、core dump找bug1、开启core文件2、永久生效的方法3、编写测试程序4、运行结果5、查看core段错误位置6、在程序中开启core dump并二者core文件大小 三、gdbserv…...
软件工程师中级考试-上午知识点总结(上)
我总结的这些都是每年的考点,必须要记下来的。 1. 计算机系统基础 1.1 码 符号位0表示正数,符号位1表示负数。补码:简化运算部件的设计,最适合进行数字加减运算。移码:与前几种不同,1表示,0表…...
Python+CoppeliaSim+ZMQ remote API控制机器人跳舞
这是一个使用Python和CoppeliaSim(V-REP)控制ASTI人型机器人进行舞蹈动作的演示项目。 项目描述 本项目展示了如何使用Python通过ZeroMQ远程API与CoppeliaSim仿真环境进行交互,控制ASTI人型机器人执行预定义的舞蹈动作序列。项目包含完整的机…...
基于FreeRTOS和STM32的微波炉
一、项目简介 使用STM32F103C8T6、舵机、继电器、加热片、蜂鸣器、两个按键、LCD及DHT11传感器等硬件。进一步,结合FreeRTOS和状态机等软件实现了一个微波炉系统;实现的功能包含:人机交互、时间及功率设置、异常情况处理及固件升级等。 二、…...
维度建模工具箱 提纲与总结
这里写自定义目录标题 基本概念事实表和维度表BI(Business Intelligence) 产品 事实表事实表的粒度事实表的种类 维度表建模技术基本原则避免用自然键作为维度表的主键,而要使用类似自增的整数键避免过度规范化避免变成形同事实表的维度表 SCD(Slowly Changed Dimen…...
【沉浸式求职学习day21】【常用类分享,完结!】
沉浸式求职学习 String类(完结) 和 equals的区别 StringBuffer日期类DateCalendar File类 String类(完结) 上次讲了一些创建String类实例的方法。 今天要分享的第一个点是常考的关于String的面试题 和 equals的区别 首先是&…...
国防科大清华城市空间无人机导航推理!GeoNav:赋予多模态大模型地理空间推理能力,实现语言指令导向的空中目标导航
作者: Haotian Xu 1 ^{1} 1, Yue Hu 1 ^{1} 1, Chen Gao 2 ^{2} 2, Zhengqiu Zhu 1 ^{1} 1, Yong Zhao 1 ^{1} 1, Yong Li 2 ^{2} 2, Quanjun Yin 1 ^{1} 1单位: 1 ^{1} 1国防科技大学系统工程学院, 2 ^{2} 2清华大学论文标题:Geo…...
uniapp打ios包
uniapp在windows电脑下申请证书并打包上架 前言 该开发笔记记录了在window系统下,在苹果开发者网站生成不同证书,进行uniapp打包调试和上线发布,对window用户友好 注:苹果打包涉及到两种证书:开发证书 和 分发证书 …...
Redis 的指令执行方式:Pipeline、事务与 Lua 脚本的对比
Pipeline 客户端将多条命令打包发送,服务器顺序执行并一次性返回所有结果。可以减少网络往返延迟(RTT)以提升吞吐量。 需要注意的是,Pipeline 中的命令按顺序执行,但中间可能被其他客户端的命令打断。 典型场景&…...
(14)VTK C++开发示例 --- 将点投影到平面上
文章目录 1. 概述2. CMake链接VTK3. main.cpp文件4. 演示效果 更多精彩内容👉内容导航 👈👉VTK开发 👈 1. 概述 计算一个点在一个平面上的投影。 vtkPlane 是 VTK(Visualization Toolkit)库中的一个类&…...
快速搭建 Cpolar 内网穿透(Mac 系统)
1、Cpolar快速入门教程(官方) 链接地址:Cpolar 快速入门 2、官方教程详解 本地安装homebrew /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"这个是从 git 上拉取的&#x…...
【Flink SQL实战】 UTC 时区格式的 ISO 时间转东八区时间
文章目录 一、原始数据格式二、解决方案三、其他要求 在实际开发中,我们常常会遇到此类情况:数据源里的时间格式是类似 2025-04-21T09:23:16.025Z 这种带 TimeZone 标识的 ISO 8601 格式,而我们需要在 Flink SQL 中将其转换成北京时间显示。 …...
动态监控进程
1.介绍: top和ps命令很相似,它们都是用来显示正在执行的进程,top和ps最大的不同之处,在于top在执行中可以更新正在执行的进程. 2.基本语法: top [选项] 选项说明 ⭐️僵死进程:内存没有释放,但是进程已经停止工作了,需要及时清理 交互操作说明 应用案…...
HADOOP 3.4.1安装和搭建(尚硅谷版~)
目录 1.配置模版虚拟机 2.克隆虚拟机 3.在hadoop102安装JDK 4.完全分布式运行模式 1.配置模版虚拟机 1.安装模板虚拟机,IP地址192.168.10.100、主机名称hadoop100、内存2G、硬盘20G(有需求的可以配置4G内存,50G硬盘) 2.hado…...
第 4 篇:平稳性 - 时间序列分析的基石
第 4 篇:平稳性 - 时间序列分析的基石 在上一篇中,我们学习了如何将时间序列分解为趋势、季节性和残差。我们看到,很多真实世界的时间序列(比如 CO2 浓度)都包含明显的趋势(长期向上或向下)和/…...
