1. 模式定义与核心思想
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当这个主题对象的状态发生变化时,它会自动通知所有观察者对象,使它们能够自动更新自己。
核心思想: 解耦主题和观察者。主题不需要知道哪些具体对象在观察它,它只需要维护一个观察者列表,并在状态改变时向它们发送通知。这使得系统更灵活,可以动态地添加和删除观察者,而无需修改主题的代码。
2. 模式结构(角色分析)
观察者模式通常包含以下四个角色:
Subject (主题 / 被观察者):
维护一个观察者(Observer)对象的集合。
提供接口可以添加(Attach)和删除(Detach)观察者。
提供接口用于通知(Notify)所有注册的观察者。
ConcreteSubject (具体主题):
继承自 Subject。
维护其自身的状态(例如,一个温度值、一个鼠标点击位置)。
当状态发生改变时,调用父类的 Notify 方法通知所有观察者。
Observer (观察者):
为所有具体观察者定义一个更新接口。通常是一个抽象的 Update() 方法。
当接到主题的通知时,调用此方法做出响应。
ConcreteObserver (具体观察者):
继承自 Observer。
实现 Update() 方法。在此方法中,通常会从 ConcreteSubject 获取所需的状态,并执行具体的业务逻辑(如更新UI、记录日志等)。
通常会维护一个指向 ConcreteSubject 的引用,以便在更新时获取其状态。
它们之间的协作关系如下图所示:
(这是一个UML协作序列的文本描述)
ConcreteObserver 调用 ConcreteSubject 的 Attach 方法将自己注册到主题的观察者列表中。
ConcreteSubject 的内部状态发生变化。
ConcreteSubject 调用 Notify 方法。
Notify 方法遍历所有注册的 Observer,并调用每个观察者的 Update 方法。
ConcreteObserver 的 Update 方法被调用,它可以通过传入的参数或查询 ConcreteSubject 来获取新状态,并据此更新自身。
3. 经典C++实现示例
下面是一个简单的C++实现,模拟一个气象站(主题)和多个显示设备(观察者)。
#include <iostream>
#include <vector>
#include <string>
#include <memory>
// 前向声明
class Subject;
// 1. Observer (观察者接口)
class Observer {
public:
virtual ~Observer() = default;
// 更新接口,参数通常是Subject或状态数据
virtual void Update(Subject& subject) = 0;
};
// 2. Subject (主题接口)
class Subject {
public:
virtual ~Subject() = default;
// 注册观察者
void Attach(std::shared_ptr<Observer> observer) {
observers_.push_back(observer);
}
// 移除观察者
void Detach(std::shared_ptr<Observer> observer) {
// 在实际项目中,这里需要更安全的删除逻辑
observers_.erase(
std::remove(observers_.begin(), observers_.end(), observer),
observers_.end());
}
// 通知所有观察者
void Notify() {
for (auto& observer : observers_) {
observer->Update(*this);
}
}
private:
std::vector<std::shared_ptr<Observer>> observers_;
};
// 3. ConcreteSubject (具体主题:气象站)
class WeatherStation : public Subject {
public:
// 设置状态(温度)并通知观察者
void SetTemperature(double temp) {
temperature_ = temp;
Notify(); // 关键一步:状态改变,立即通知所有观察者
}
// 获取状态(供观察者查询)
double GetTemperature() const {
return temperature_;
}
private:
double temperature_ = 0.0;
};
// 4. ConcreteObserver (具体观察者:手机显示)
class PhoneDisplay : public Observer {
public:
explicit PhoneDisplay(const std::string& name) : name_(name) {}
void Update(Subject& subject) override {
// 安全的向下转型,确认主题类型
WeatherStation* ws = dynamic_cast<WeatherStation*>(&subject);
if (ws) {
double temp = ws->GetTemperature();
std::cout << "[" << name_ << "] Temperature updated: " << temp << "°C\n";
}
}
private:
std::string name_;
};
// 5. 另一个具体观察者:LED大屏显示
class LedDisplay : public Observer {
public:
void Update(Subject& subject) override {
WeatherStation* ws = dynamic_cast<WeatherStation*>(&subject);
if (ws) {
double temp = ws->GetTemperature();
std::cout << "*** LED Display: CURRENT TEMP = " << temp << "°C ***\n";
}
}
};
// 客户端代码
int main() {
// 创建主题(气象站)
WeatherStation station;
// 创建观察者(两个显示设备)
auto phone1 = std::make_shared<PhoneDisplay>("User's Phone");
auto phone2 = std::make_shared<PhoneDisplay>("Dad's Phone");
auto led = std::make_shared<LedDisplay>();
// 注册观察者
station.Attach(phone1);
station.Attach(phone2);
station.Attach(led);
// 模拟气象站温度变化,观察者会自动更新
std::cout << "Setting temperature to 25.5°C...\n";
station.SetTemperature(25.5);
std::cout << "\nSetting temperature to 18.2°C...\n";
station.SetTemperature(18.2);
// 移除一个观察者
std::cout << "\nDetaching Dad's Phone...\n";
station.Detach(phone2);
std::cout << "Setting temperature to 30.0°C...\n";
station.SetTemperature(30.0);
return 0;
}
输出结果:
Setting temperature to 25.5°C...
[User's Phone] Temperature updated: 25.5°C
[Dad's Phone] Temperature updated: 25.5°C
*** LED Display: CURRENT TEMP = 25.5°C ***
Setting temperature to 18.2°C...
[User's Phone] Temperature updated: 18.2°C
[Dad's Phone] Temperature updated: 18.2°C
*** LED Display: CURRENT TEMP = 18.2°C ***
Detaching Dad's Phone...
Setting temperature to 30.0°C...
[User's Phone] Temperature updated: 30°C
*** LED Display: CURRENT TEMP = 30°C ***
更多例子:
示例 1: GUI 事件处理 (按钮点击)
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
// 前向声明
class Button;
// 观察者接口:事件监听器
class EventListener {
public:
virtual ~EventListener() = default;
virtual void onClick(Button& source) = 0;
};
// 主题:按钮
class Button {
std::vector<EventListener*> listeners_; // 使用原始指针简化示例
std::string name_;
public:
Button(const std::string& name) : name_(name) {}
// 注册观察者
void addListener(EventListener* listener) {
listeners_.push_back(listener);
}
// 移除观察者
void removeListener(EventListener* listener) {
listeners_.erase(std::remove(listeners_.begin(), listeners_.end(), listener), listeners_.end());
}
// 模拟用户点击
void click() {
std::cout << "Button '" << name_ << "' was clicked!\n";
notifyListeners();
}
const std::string& getName() const { return name_; }
private:
// 通知所有观察者
void notifyListeners() {
for (auto listener : listeners_) {
listener->onClick(*this);
}
}
};
// 具体观察者:登录处理器
class LoginHandler : public EventListener {
public:
void onClick(Button& source) override {
std::cout << "[LoginHandler] Handling click from: " << source.getName() << "\n";
std::cout << "Performing login logic...\n";
}
};
// 具体观察者:日志记录器
class ClickLogger : public EventListener {
public:
void onClick(Button& source) override {
std::cout << "[ClickLogger] Button clicked: " << source.getName() << " at timestamp: 12345\n";
}
};
int main() {
Button loginButton("Login");
LoginHandler loginHandler;
ClickLogger logger;
// 注册监听器
loginButton.addListener(&loginHandler);
loginButton.addListener(&logger);
// 模拟点击事件
loginButton.click();
std::cout << "\nRemoving logger...\n";
loginButton.removeListener(&logger);
loginButton.click();
return 0;
}
输出结果:
Button 'Login' was clicked!
[LoginHandler] Handling click from: Login
Performing login logic...
[ClickLogger] Button clicked: Login at timestamp: 12345
Removing logger...
Button 'Login' was clicked!
[LoginHandler] Handling click from: Login
Performing login logic...
示例 2: 发布-订阅系统 (简单的消息主题)
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <algorithm>
// 消息类
struct Message {
std::string topic;
std::string content;
};
// 订阅者接口
class Subscriber {
public:
virtual ~Subscriber() = default;
virtual void onMessage(const Message& msg) = 0;
};
// 消息代理(主题)
class MessageBroker {
std::map<std::string, std::vector<Subscriber*>> topicSubscribers_;
public:
// 订阅主题
void subscribe(const std::string& topic, Subscriber* sub) {
topicSubscribers_[topic].push_back(sub);
}
// 取消订阅
void unsubscribe(const std::string& topic, Subscriber* sub) {
auto& subs = topicSubscribers_[topic];
subs.erase(std::remove(subs.begin(), subs.end(), sub), subs.end());
}
// 发布消息
void publish(const Message& msg) {
auto it = topicSubscribers_.find(msg.topic);
if (it != topicSubscribers_.end()) {
for (auto sub : it->second) {
sub->onMessage(msg);
}
}
}
};
// 具体订阅者:日志服务
class LogService : public Subscriber {
public:
void onMessage(const Message& msg) override {
std::cout << "[LogService] Received on topic '" << msg.topic << "': " << msg.content << "\n";
}
};
// 具体订阅者:告警服务
class AlertService : public Subscriber {
public:
void onMessage(const Message& msg) override {
if (msg.topic == "alerts") {
std::cout << "[AlertService] ALERT! " << msg.content << "\n";
}
}
};
int main() {
MessageBroker broker;
LogService logger;
AlertService alerter;
// 订阅主题
broker.subscribe("logs", &logger);
broker.subscribe("alerts", &logger);
broker.subscribe("alerts", &alerter);
// 发布消息
broker.publish({"logs", "System started successfully"});
broker.publish({"alerts", "CPU usage over 90%"});
broker.publish({"metrics", "This will be ignored by all"}); // 无订阅者
return 0;
}
输出结果:
[LogService] Received on topic 'logs': System started successfully
[LogService] Received on topic 'alerts': CPU usage over 90%
[AlertService] ALERT! CPU usage over 90%