观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象(被观察者)的状态发生变化时,所有依赖它的对象(观察者)会自动收到通知并更新。
这种模式的核心是解耦被观察者和观察者,让它们可以独立变化而互不影响。
核心角色
-
Subject(被观察者/主题):
- 维护一个观察者列表
- 提供添加、移除观察者的方法
- 提供通知所有观察者的方法
-
Observer(观察者):
- 定义接收通知的接口
- 当收到被观察者通知时执行相应操作
-
ConcreteSubject(具体被观察者):
- 实现被观察者接口
- 维护自身状态,状态变化时通知观察者
-
ConcreteObserver(具体观察者):
- 实现观察者接口
- 定义收到通知后的具体处理逻辑
C++实现示例
以下是一个简单的气象站示例,气象站(被观察者)会将温度变化通知给多个显示器(观察者):
#include <iostream>
#include <vector>
#include <string>
// 前向声明
class Subject;
// 观察者接口
class Observer {
public:
virtual ~Observer() = default;
virtual void update(float temperature) = 0; // 接收温度更新
};
// 被观察者接口
class Subject {
public:
virtual ~Subject() = default;
virtual void registerObserver(Observer* observer) = 0; // 注册观察者
virtual void removeObserver(Observer* observer) = 0; // 移除观察者
virtual void notifyObservers() = 0; // 通知所有观察者
};
// 具体被观察者:气象站
class WeatherStation : public Subject {
private:
std::vector<Observer*> observers; // 观察者列表
float temperature; // 温度状态
public:
void registerObserver(Observer* observer) override {
observers.push_back(observer);
}
void removeObserver(Observer* observer) override {
// 查找并移除观察者
for (auto it = observers.begin(); it != observers.end(); ++it) {
if (*it == observer) {
observers.erase(it);
break;
}
}
}
void notifyObservers() override {
// 通知所有观察者
for (auto observer : observers) {
observer->update(temperature);
}
}
// 温度变化时调用,触发通知
void setTemperature(float temp) {
temperature = temp;
std::cout << "气象站:温度更新为 " << temperature << "℃" << std::endl;
notifyObservers(); // 通知所有观察者
}
};
// 具体观察者:手机显示器
class PhoneDisplay : public Observer {
private:
std::string name;
float currentTemp;
public:
PhoneDisplay(const std::string& n) : name(n), currentTemp(0) {}
void update(float temperature) override {
currentTemp = temperature;
display();
}
void display() {
std::cout << name << " 手机显示:当前温度 " << currentTemp << "℃" << std::endl;
}
};
// 具体观察者:电脑显示器
class ComputerDisplay : public Observer {
private:
float currentTemp;
public:
ComputerDisplay() : currentTemp(0) {}
void update(float temperature) override {
currentTemp = temperature;
display();
}
void display() {
std::cout << "电脑显示:当前温度 " << currentTemp << "℃,"
<< (currentTemp > 30 ? "天气炎热" : "温度适宜") << std::endl;
}
};
int main() {
// 创建被观察者(气象站)
WeatherStation weatherStation;
// 创建观察者(显示器)
PhoneDisplay phone1("小明的手机");
PhoneDisplay phone2("小红的手机");
ComputerDisplay computer;
// 注册观察者
weatherStation.registerObserver(&phone1);
weatherStation.registerObserver(&phone2);
weatherStation.registerObserver(&computer);
// 温度变化,自动通知所有观察者
std::cout << "----- 第一次温度变化 -----" << std::endl;
weatherStation.setTemperature(25.5f);
std::cout << "\n----- 移除小红的手机 -----" << std::endl;
weatherStation.removeObserver(&phone2);
std::cout << "\n----- 第二次温度变化 -----" << std::endl;
weatherStation.setTemperature(32.0f);
return 0;
}
代码解析
-
Observer接口 :定义了
update
方法,所有观察者都必须实现该方法以接收通知。 -
Subject接口:定义了管理观察者的方法(注册、移除、通知),是被观察者的抽象。
-
WeatherStation :具体的被观察者,维护温度状态和观察者列表,当温度变化时会调用
notifyObservers
通知所有注册的观察者。 -
PhoneDisplay和ComputerDisplay :具体的观察者,实现了
update
方法,在收到温度更新时会执行各自的显示逻辑。
观察者模式的优缺点
优点:
- 实现了被观察者和观察者的解耦,两者可以独立变化
- 观察者数量可动态增减,灵活性高
- 支持广播通信,被观察者的状态变化可同时通知多个观察者
缺点:
- 如果观察者数量过多,通知过程可能耗时较长
- 观察者之间没有优先级,无法指定通知顺序
- 可能导致多余的更新通知(即使观察者不需要该状态)
适用场景
- 当一个对象的状态变化需要触发多个其他对象的更新时(如事件监听)
- 当需要动态建立对象间的依赖关系时(如订阅/取消订阅功能)
- 当一个对象必须通知其他对象,但又不知道这些对象是谁时
常见应用:GUI事件处理(按钮点击触发多个响应)、消息通知系统、股票价格更新、RSS订阅等。