第一部分:基础概念与实现
1. 概念定义
观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生变化时,会通知所有观察者,使它们能够自动更新自己。
2. 核心组成
Subject
-observers: List<Observer>
+attach(Observer)
+detach(Observer)
+notify()
<<interface>>
Observer
+update()
ConcreteSubject
-state: State
+getState()
+setState()
ConcreteObserver
-state: State
+update()
3. 工作原理流程图
Observer2 Observer1 Subject Client Observer2 Observer1 Subject Client attach(Observer1) attach(Observer2) setState(newState) update() getState() return state update() getState() return state
4. 应用场景
- 事件处理系统:GUI程序中的按钮点击、键盘输入等事件
- 发布-订阅系统:消息队列、事件总线
- 数据同步:多个视图需要实时更新同一份数据
- 游戏开发:角色状态变化通知UI更新
- MVC架构:Model变化时通知View更新
5. C++完整实现
cpp
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
// 前向声明
class Observer;
// 主题接口(被观察者)
class Subject {
public:
virtual ~Subject() = default;
virtual void attach(Observer* observer) = 0;
virtual void detach(Observer* observer) = 0;
virtual void notify() = 0;
};
// 观察者接口
class Observer {
public:
virtual ~Observer() = default;
virtual void update(int value) = 0;
};
// 具体主题:天气站
class WeatherStation : public Subject {
private:
std::vector<Observer*> observers;
int temperature;
public:
WeatherStation() : temperature(0) {}
void attach(Observer* observer) override {
observers.push_back(observer);
std::cout << "观察者已添加" << std::endl;
}
void detach(Observer* observer) override {
auto it = std::find(observers.begin(), observers.end(), observer);
if (it != observers.end()) {
observers.erase(it);
std::cout << "观察者已移除" << std::endl;
}
}
void notify() override {
std::cout << "通知所有观察者..." << std::endl;
for (auto* observer : observers) {
observer->update(temperature);
}
}
// 业务方法:设置温度
void setTemperature(int temp) {
std::cout << "\n天气站:温度从 " << temperature
<< " 度变为 " << temp << " 度" << std::endl;
temperature = temp;
notify(); // 状态改变,通知观察者
}
};
// 具体观察者1:手机App
class PhoneApp : public Observer {
private:
std::string phoneName;
public:
PhoneApp(const std::string& name) : phoneName(name) {}
void update(int temperature) override {
std::cout << "📱 " << phoneName << " App 显示:当前温度 "
<< temperature << " 度" << std::endl;
}
};
// 具体观察者2:LED显示屏
class LEDDisplay : public Observer {
private:
std::string location;
public:
LEDDisplay(const std::string& loc) : location(loc) {}
void update(int temperature) override {
std::cout << "🖥️ " << location << " LED显示屏:温度 = "
<< temperature << "°C" << std::endl;
}
};
// 具体观察者3:报警系统
class AlertSystem : public Observer {
private:
int alertThreshold;
public:
AlertSystem(int threshold) : alertThreshold(threshold) {}
void update(int temperature) override {
if (temperature > alertThreshold) {
std::cout << "⚠️ 报警系统:高温警报!温度 " << temperature
<< " 度超过阈值 " << alertThreshold << " 度" << std::endl;
} else if (temperature < -10) {
std::cout << "⚠️ 报警系统:低温警报!温度 " << temperature
<< " 度过低,请注意保暖" << std::endl;
} else {
std::cout << "✅ 报警系统:温度正常" << std::endl;
}
}
};
// 使用示例
int main() {
// 创建主题
WeatherStation weatherStation;
// 创建观察者
PhoneApp phone1("张三的手机");
PhoneApp phone2("李四的手机");
LEDDisplay led("中央广场");
AlertSystem alert(35); // 超过35度报警
// 注册观察者
weatherStation.attach(&phone1);
weatherStation.attach(&phone2);
weatherStation.attach(&led);
weatherStation.attach(&alert);
// 模拟温度变化
weatherStation.setTemperature(25);
weatherStation.setTemperature(38);
weatherStation.setTemperature(-15);
// 移除一个观察者
weatherStation.detach(&phone2);
std::cout << "\n=== 移除李四手机后 ===" << std::endl;
weatherStation.setTemperature(20);
return 0;
}
6. 现代C++改进版本(使用智能指针和函数式)
cpp
#include <iostream>
#include <vector>
#include <memory>
#include <functional>
#include <algorithm>
// 使用函数式观察者(更灵活)
class WeatherStationModern {
private:
std::vector<std::function<void(int)>> callbacks;
int temperature;
public:
void subscribe(std::function<void(int)> callback) {
callbacks.push_back(callback);
}
void setTemperature(int temp) {
temperature = temp;
notify();
}
void notify() {
for (const auto& callback : callbacks) {
callback(temperature);
}
}
};
int main() {
WeatherStationModern station;
// 使用lambda表达式作为观察者
station.subscribe([](int temp) {
std::cout << "Lambda观察者1:温度是 " << temp << "°C" << std::endl;
});
station.subscribe([](int temp) {
if (temp > 30) {
std::cout << "Lambda观察者2:天气很热!" << std::endl;
}
});
station.setTemperature(28);
station.setTemperature(35);
return 0;
}
7. 传统版本的优缺点
优点:
- ✅ 满足开闭原则,添加新观察者无需修改主题
- ✅ 松耦合,主题和观察者可以独立变化
- ✅ 支持广播通信
缺点:
- ❌ 观察者过多时通知开销大
- ❌ 如果观察者之间有依赖,需要注意通知顺序
- ❌ 可能造成循环依赖或意外更新
8. 注意事项
- 避免循环引用 :使用原始指针或
weak_ptr防止内存泄漏 - 异常安全:确保一个观察者异常不影响其他观察者
- 线程安全:多线程环境下需要加锁保护观察者列表
- 通知顺序:通常不保证观察者更新顺序
第二部分:思想思维深度解析
1. 核心思想:从"主动轮询"到"被动通知"
观察者模式最根本的思维转变是逆转了控制流:
观察者思维
状态改变时主动通知
数据源
客户端
传统轮询思维
不断询问
返回状态
客户端
数据源
传统思维的困境:
cpp
// 传统轮询方式 - 浪费资源
while(true) {
if (weatherStation.getTemperature() != lastTemp) {
updateDisplay();
}
sleep(1); // 要么延迟导致响应慢,要么频繁检查浪费CPU
}
观察者思维的优势:
cpp
// 事件驱动方式 - 精确响应
void onTemperatureChanged(int newTemp) {
updateDisplay(); // 只在变化时执行
}
2. 哲学层面的思考
"好莱坞原则"(Don't call us, we'll call you)
- 传统:底层组件主动调用高层组件
- 观察者:高层组件告诉底层组件"有变化通知我",底层反过来通知高层
"观察"与"被观察"的关系本质
现实世界的映射
编辑部与订阅者
股票交易所与显示屏
传感器与监控中心
发布-订阅模式
观察者模式
3. 思维模型的三个层次
第一层:技术视角(What)
- 接口分离:Subject和Observer接口
- 动态注册:运行时添加/移除观察者
- 广播机制:一对多通知
第二层:架构视角(How)
cpp
// 思维模型:事件总线架构
class EventBus {
// 所有通信都通过这个"中介"
// 让组件之间完全解耦
};
// vs 直接耦合
class Button {
Display* display; // 按钮直接依赖显示器(紧耦合)
void onClick() {
display->update();
}
};
第三层:业务视角(Why)
cpp
// 业务需求:电商促销系统
class ProductPrice {
// 当价格变化时需要通知:
// 1. 购物车(重新计算总价)
// 2. 推荐系统(更新推荐)
// 3. 价格追踪器(记录历史)
// 4. 邮件通知(订阅降价提醒)
// 使用观察者思维:价格只负责"通知变化"
// 不关心谁会响应
};
4. 与其他模式的关系思维
思维延伸
变体形式
常与结合
对比理解
Model通知View更新
引入Broker解耦
集中控制通信
函数指针方式
观察者模式
MVC模式
发布-订阅模式
中介者模式
回调机制
5. 常见误区与深化理解
误区1:观察者只是回调函数的包装
cpp
// 错误认知:简单回调就够了
void onEvent(std::function<void()> callback);
// 正确理解:观察者模式强调的是"可管理的依赖关系"
class Observable {
vector<Observer> observers; // 可管理列表
// 支持:注册、注销、优先级、条件通知等
};
误区2:观察者必须是被动更新
cpp
// 主动拉取 vs 被动推送
class SmartObserver {
void update(Subject* sub) override {
// 主动决定要获取什么数据
int needed = sub->getSpecificData();
// 而不是被动接受所有数据
}
};
6. 高级思维:观察者模式的变体
异步观察者
cpp
// 思维:通知不应该阻塞主体
class AsyncSubject {
void notify() {
for (auto& obs : observers) {
thread_pool.submit([&obs] {
obs->update(); // 异步执行
});
}
}
};
条件观察者
cpp
// 思维:只有满足条件才通知
class ConditionalSubject {
void notify(int value) {
for (auto& obs : observers) {
if (obs->interest(value)) { // 观察者声明兴趣
obs->update(value);
}
}
}
};
7. 现实世界的类比思维
真实世界类比
思维
思维
思维
思维
YouTube频道
观察者模式
微信群消息
观察者模式
股票盯盘
观察者模式
传感器网络
观察者模式
核心思维提取:
- 关注点分离:发布者只管发布,订阅者只管处理
- 动态性:可以随时订阅/取消订阅
- 松耦合:双方不知道对方的具体实现
- 扩展性:新增订阅者不影响发布者
8. 思维训练:何时不应该使用
cpp
// 反模式1:只有一个观察者
class SingletonObserver {
// 此时观察者模式过度设计
};
// 反模式2:同步紧耦合的需求
class TightCoupled {
void operation() {
step1();
step2(); // 必须立即同步执行
step3();
}
// 观察者模式的异步通知会破坏顺序
};
9. 思维升华:事件驱动架构的基础
观察者模式是事件驱动架构的最小单元:
观察者模式
CQRS模式
事件溯源
事件驱动架构
微服务架构
终极思维:将系统看作"事件流"而非"状态机"
- 传统思维:当前温度是25度(关注状态)
- 观察者思维:温度从20变到25度(关注事件)
10. 实践建议
- 从简单开始:先使用函数回调,重构到观察者模式
- 识别变化点:找出系统中"经常变化"和"需要响应变化"的部分
- 命名很重要 :使用业务语言(
onPriceChanged而非notify) - 文档化通知顺序:明确观察者的执行顺序是否有要求
- 考虑线程安全:多线程环境下的观察者列表保护
总结
思维总结 :观察者模式的核心不是技术实现,而是认识到系统中存在独立变化 和依赖于变化的两类组件,通过建立"通知-响应"的契约,让系统能够灵活演化。
观察者模式是设计模式中最常用的一种,理解它对于构建可扩展、松耦合的系统至关重要。从基础实现到深层思维,这个模式教会我们如何构建真正灵活、可维护的软件系统。