观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象间的一对多依赖关系,当一个对象(主题)状态改变时,所有依赖它的对象(观察者)都会自动得到通知并更新。
核心概念
设计原则
观察者模式遵循以下设计原则:
松耦合:主题和观察者之间松耦合
开闭原则:可以新增观察者而不修改主题
抽象耦合:主题只依赖观察者抽象接口
主要优点
动态订阅:观察者可动态订阅或取消订阅
广播通信:主题可通知多个观察者
解耦:分离观察者和被观察者
事件处理:适用于事件驱动系统
模式结构
主要组件
Subject(主题/被观察者)
维护观察者列表
提供注册/注销观察者的接口
状态改变时通知观察者
Observer(观察者接口)
定义更新接口
ConcreteObserver(具体观察者)
实现更新接口
维护对主题的引用(可选)
完整代码示例
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
#include <string>
// ==================== 观察者接口 ====================
class Observer {
public:
virtual void update(const std::string& message) = 0;
virtual ~Observer() = default;
};
// ==================== 主题接口 ====================
class Subject {
std::vector<Observer*> observers_;
std::string state_;
public:
void attach(Observer* observer) {
observers_.push_back(observer);
}
void detach(Observer* observer) {
observers_.erase(
std::remove(observers_.begin(), observers_.end(), observer),
observers_.end());
}
void notify() {
for (auto observer : observers_) {
observer->update(state_);
}
}
void setState(const std::string& state) {
state_ = state;
notify();
}
std::string getState() const {
return state_;
}
};
// ==================== 具体观察者 ====================
class ConcreteObserver : public Observer {
std::string name_;
std::string observerState_;
Subject* subject_;
public:
ConcreteObserver(const std::string& name, Subject* subject)
: name_(name), subject_(subject) {
subject_->attach(this);
}
~ConcreteObserver() {
if (subject_) {
subject_->detach(this);
}
}
void update(const std::string& message) override {
observerState_ = message;
std::cout << "观察者 " << name_ << " 收到更新: " << observerState_ << std::endl;
}
void unsubscribe() {
if (subject_) {
subject_->detach(this);
subject_ = nullptr;
}
}
};
// ==================== 客户端代码 ====================
int main() {
std::cout << "=== 观察者模式演示 ===" << std::endl;
// 创建主题
Subject subject;
// 创建观察者
ConcreteObserver observer1("观察者1", &subject);
ConcreteObserver observer2("观察者2", &subject);
ConcreteObserver observer3("观察者3", &subject);
// 改变主题状态,观察者会自动收到通知
std::cout << "\n第一次状态改变:" << std::endl;
subject.setState("状态1");
// 观察者2取消订阅
observer2.unsubscribe();
// 再次改变状态
std::cout << "\n第二次状态改变(观察者2已取消订阅):" << std::endl;
subject.setState("状态2");
// 动态添加新观察者
std::cout << "\n添加新观察者:" << std::endl;
ConcreteObserver observer4("观察者4", &subject);
subject.setState("状态3");
return 0;
}
模式变体
1. 推模型 vs 拉模型
// 推模型 - 主题将详细数据推送给观察者
class PushObserver {
public:
virtual void update(int temp, int humidity, float pressure) = 0;
};
// 拉模型 - 观察者从主题拉取所需数据
class PullObserver {
public:
virtual void update(Subject* subject) = 0; // 观察者自己获取数据
};
2. 使用智能指针管理观察者
class SafeSubject {
std::vector<std::weak_ptr<Observer>> observers_;
void notify() {
auto it = observers_.begin();
while (it != observers_.end()) {
if (auto observer = it->lock()) {
observer->update(state_);
++it;
} else {
it = observers_.erase(it);
}
}
}
};
3. 线程安全的观察者模式
#include <mutex>
class ThreadSafeSubject {
std::vector<Observer*> observers_;
mutable std::mutex mtx_;
public:
void attach(Observer* observer) {
std::lock_guard<std::mutex> lock(mtx_);
observers_.push_back(observer);
}
void notify() {
std::vector<Observer*> observersCopy;
{
std::lock_guard<std::mutex> lock(mtx_);
observersCopy = observers_;
}
for (auto observer : observersCopy) {
observer->update(state_);
}
}
};
实际应用场景
GUI事件处理:按钮点击、键盘输入等事件监听
发布-订阅系统:消息队列、新闻推送
股票行情更新:股价变动通知投资者
游戏引擎:游戏状态变化通知UI更新
分布式系统:配置变更通知多个节点