C++中的观察者模式:通俗易懂的讲解与实现
什么是观察者模式?
观察者模式是一种常见的设计模式,它解决了这样一个问题:当某个对象的状态发生变化时,如何通知依赖它的其他对象?
用通俗的话说,观察者模式就像我们日常的“订阅-通知”机制:
- 主题(Subject) 是信息的提供者(比如新闻网站、天气站)。
- 观察者(Observer) 是信息的订阅者(比如读者、天气App)。
- 当主题有了新的变化(如新闻更新、天气变化),会通知所有订阅的观察者。
观察者模式的特点
-
松耦合
主题和观察者之间通过接口交互,彼此不直接依赖,可以独立扩展。 -
动态订阅与取消订阅
观察者可以随时订阅或取消订阅,运行时非常灵活。 -
通知机制自动化
主题变化后,会统一通知所有订阅者。
适用场景
-
消息通知
比如新闻推送系统,用户订阅后,新闻更新会自动推送。 -
数据驱动更新
在界面设计中,数据变化时需要动态更新UI(如MVC架构)。 -
事件触发系统
游戏中玩家状态变化需要通知其他玩家,或者股票系统推送实时行情。
C++实现观察者模式:天气预报案例
为了演示观察者模式,我们用一个天气预报系统来举例:
- 主题(WeatherStation): 模拟一个天气站,用于监控和更新天气。
- 观察者(WeatherApp): 模拟订阅天气的手机App,接收天气通知。
完整代码
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
#include <string>
// 抽象观察者接口
class WeatherObserver {
public:
virtual void updateWeather(const std::string& weather) = 0; // 收到天气更新通知的方法
virtual ~WeatherObserver() = default;
};
// 抽象主题类(天气站)
class WeatherStation {
private:
std::vector<std::shared_ptr<WeatherObserver>> observers; // 保存订阅者列表
std::string currentWeather; // 当前天气
public:
// 添加观察者(订阅)
void addObserver(std::shared_ptr<WeatherObserver> observer) {
observers.push_back(observer);
}
// 移除观察者(取消订阅)
void removeObserver(std::shared_ptr<WeatherObserver> observer) {
observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
}
// 通知所有观察者
void notifyObservers() {
for (const auto& observer : observers) {
observer->updateWeather(currentWeather);
}
}
// 更新天气并通知观察者
void updateWeather(const std::string& weather) {
currentWeather = weather;
notifyObservers(); // 通知所有观察者天气变化
}
};
// 具体观察者类(手机App)
class WeatherApp : public WeatherObserver {
private:
std::string appName; // App的名字
public:
explicit WeatherApp(const std::string& name) : appName(name) {}
// 实现天气更新通知方法
void updateWeather(const std::string& weather) override {
std::cout << appName << " 收到了最新天气:" << weather << std::endl;
}
};
// 主函数:测试观察者模式
int main() {
// 创建天气站(主题)
std::shared_ptr<WeatherStation> station = std::make_shared<WeatherStation>();
// 创建两个观察者(手机App)
std::shared_ptr<WeatherObserver> app1 = std::make_shared<WeatherApp>("天气宝App");
std::shared_ptr<WeatherObserver> app2 = std::make_shared<WeatherApp>("气象通App");
// 两个App订阅天气站
station->addObserver(app1);
station->addObserver(app2);
// 更新天气,触发通知
station->updateWeather("晴天");
station->updateWeather("下雨");
// 取消天气宝App的订阅
station->removeObserver(app1);
// 再次更新天气,验证通知
station->updateWeather("大风");
return 0;
}
代码拆解与分析
-
抽象观察者接口(
WeatherObserver
)- 定义了一个虚函数
updateWeather()
,所有观察者类都必须实现这个方法,用来接收通知。
- 定义了一个虚函数
-
主题类(
WeatherStation
)- 保存了一个观察者列表(
std::vector
),用于管理所有订阅者。 - 提供了
addObserver()
和removeObserver()
方法,方便动态添加或移除观察者。 - 通过
notifyObservers()
方法通知所有观察者。
- 保存了一个观察者列表(
-
具体观察者(
WeatherApp
)- 每个观察者都实现了
updateWeather()
方法,用来处理天气变化的通知。
- 每个观察者都实现了
-
运行逻辑
- 创建主题和观察者。
- 观察者订阅主题。
- 当主题状态改变时,所有观察者都会收到更新通知。
程序运行结果
运行程序后输出如下:
天气宝App 收到了最新天气:晴天
气象通App 收到了最新天气:晴天
天气宝App 收到了最新天气:下雨
气象通App 收到了最新天气:下雨
气象通App 收到了最新天气:大风
可以看到:
- 两个App订阅后,天气更新时都会收到通知。
- 取消天气宝App的订阅后,只有气象通App收到通知。
优缺点
优点
- 松耦合设计
- 主题和观察者通过接口交互,方便扩展和维护。
- 动态订阅机制
- 可随时添加或移除观察者。
- 统一通知
- 通知逻辑集中管理,简单直观。
缺点
- 性能开销
- 如果观察者过多,通知过程可能带来性能问题。
- 依赖复杂
- 观察者之间可能产生隐式依赖关系,增加调试难度。
应用场景
-
消息推送系统:
比如新闻网站向订阅用户推送最新动态。 -
实时数据更新:
数据变化时需要更新多个UI组件。 -
事件监听机制:
游戏中角色状态改变时通知其他玩家或系统。
总结
观察者模式是一个简单却功能强大的模式,它通过“发布-订阅”机制解耦了对象之间的依赖,使得代码更加灵活和易维护。在C++中,我们可以通过抽象接口和容器来实现观察者模式,并根据需求灵活扩展。
通过本文的天气预报示例,相信你已经掌握了观察者模式的核心概念及其实现方法!