观察者设计模式详解
观察者设计模式是一种行为设计模式,用于定义对象间的一对多依赖关系。当一个对象(主题)的状态发生变化时,所有依赖它的对象(观察者)都会自动收到通知并更新。
1. 功能和作用
- 功能:实现对象间的松耦合通信。主题对象维护一个观察者列表,当状态改变时自动通知所有注册的观察者,触发其更新操作。
- 作用 :
- 解耦:主题和观察者不直接依赖具体实现,只通过接口交互。
- 动态管理:支持运行时添加或删除观察者。
- 自动更新:确保依赖对象的状态一致性,无需手动轮询。
2. 原理
观察者模式基于发布-订阅机制:
- 主题(Subject)维护一个观察者集合。
- 观察者(Observer)注册到主题上。
- 当主题状态改变时,调用
notify方法遍历观察者列表,依次调用每个观察者的update方法。 - 观察者通过
update方法获取主题的最新状态并执行相应操作。
3. 使用方式
使用观察者模式需定义以下组件:
- Subject 接口 :声明
attach,detach,notify方法,用于管理观察者。 - Observer 接口 :声明
update方法,用于响应主题通知。 - ConcreteSubject 类 :实现 Subject 接口,管理状态和观察者列表;状态改变时调用
notify。 - ConcreteObserver 类 :实现 Observer 接口,在
update方法中定义具体响应逻辑。
使用步骤:
- 创建主题和观察者对象。
- 观察者通过
attach方法注册到主题。 - 主题状态改变时自动通知所有观察者。
- 观察者通过
detach方法取消注册。
4. 为什么这么设计
- 降低耦合:主题和观察者通过接口交互,互不知晓内部实现,符合依赖倒置原则。
- 动态扩展:可随时添加新观察者,无需修改主题代码,支持开闭原则。
- 高效通知:避免观察者轮询主题状态,减少资源消耗。
- 事件驱动:适用于异步系统,如 GUI 事件处理或实时数据更新。
5. 使用场景
观察者模式适用于以下场景:
- 事件处理系统:如按钮点击事件通知多个监听器。
- 数据监控:如传感器数据变化时通知多个显示模块。
- 发布-订阅模型:如消息队列中生产者通知多个消费者。
- 用户界面更新:如模型数据改变时更新多个视图组件。
- 游戏开发:如角色状态变化时通知 AI 系统。
6. 类图描述
观察者模式的类图包含以下类和方法:
- Subject :
- 方法:
attach(Observer*),detach(Observer*),notify() - 属性:
observers(观察者列表)
- 方法:
- ConcreteSubject :
- 继承自 Subject
- 方法:
getState(),setState()(设置状态并触发通知) - 属性:
state(具体状态)
- Observer :
- 方法:
update()
- 方法:
- ConcreteObserver :
- 继承自 Observer
- 方法:
update()(实现具体响应逻辑) - 属性:
subject(关联的主题)
类图关系:
- Subject 聚合 Observer(一对多)。
- ConcreteObserver 依赖于 ConcreteSubject。
如下类图所示:

7. 时序图描述
对象工作流程时序图描述主题状态变化时的通知过程:
- 注册阶段 :
- ConcreteObserver 调用 ConcreteSubject 的
attach方法注册。
- ConcreteObserver 调用 ConcreteSubject 的
- 状态改变阶段 :
- 客户端调用 ConcreteSubject 的
setState方法改变状态。 - ConcreteSubject 内部调用
notify。
- 客户端调用 ConcreteSubject 的
- 通知阶段 :
notify遍历观察者列表,调用每个 ConcreteObserver 的update方法。- ConcreteObserver 在
update中访问主题状态并执行操作。
时序图如下:

8. C++ 语言实现
以下 C++ 代码实现了观察者模式,使用智能指针管理内存,避免内存泄漏。代码可编译运行测试。
cpp
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
// 观察者接口
class Observer {
public:
virtual void update() = 0; // 更新方法
virtual ~Observer() = default;
};
// 主题接口
class Subject {
public:
virtual void attach(std::shared_ptr<Observer> observer) = 0; // 注册观察者
virtual void detach(std::shared_ptr<Observer> observer) = 0; // 删除观察者
virtual void notify() = 0; // 通知观察者
virtual ~Subject() = default;
};
// 具体主题类
class ConcreteSubject : public Subject {
private:
int state_ = 0; // 状态
std::vector<std::shared_ptr<Observer>> observers_; // 观察者列表
public:
void attach(std::shared_ptr<Observer> observer) override {
observers_.push_back(observer);
}
void detach(std::shared_ptr<Observer> observer) override {
auto it = std::find(observers_.begin(), observers_.end(), observer);
if (it != observers_.end()) {
observers_.erase(it);
}
}
void notify() override {
for (auto& observer : observers_) {
observer->update();
}
}
int getState() const {
return state_;
}
void setState(int state) {
state_ = state;
notify(); // 状态改变时自动通知
}
};
// 具体观察者类
class ConcreteObserver : public Observer {
private:
std::shared_ptr<ConcreteSubject> subject_; // 关联的主题
public:
ConcreteObserver(std::shared_ptr<ConcreteSubject> subject) : subject_(subject) {}
void update() override {
std::cout << "Observer updated. New state: " << subject_->getState() << std::endl;
}
};
// 测试函数
int main() {
// 创建主题和观察者
auto subject = std::make_shared<ConcreteSubject>();
auto observer1 = std::make_shared<ConcreteObserver>(subject);
auto observer2 = std::make_shared<ConcreteObserver>(subject);
// 注册观察者
subject->attach(observer1);
subject->attach(observer2);
// 改变状态,触发通知
std::cout << "Setting state to 10..." << std::endl;
subject->setState(10); // 通知所有观察者
// 删除一个观察者
subject->detach(observer1);
// 再次改变状态
std::cout << "Setting state to 20..." << std::endl;
subject->setState(20); // 只通知剩余观察者
return 0;
}
9. 编译运行测试输出
使用 g++ 编译并运行:
bash
g++ -std=c++11 -o observer_example observer_example.cpp
./observer_example
预期输出:
Setting state to 10...
Observer updated. New state: 10
Observer updated. New state: 10
Setting state to 20...
Observer updated. New state: 20
输出表明:
- 第一次
setState(10)通知了两个观察者。 - 删除
observer1后,setState(20)只通知了observer2。
10. 总结优缺点和改进
优点:
- 松耦合:主题和观察者通过接口交互,降低依赖。
- 可扩展性:易于添加新观察者,无需修改主题。
- 事件驱动:高效通知机制,避免轮询开销。
- 符合设计原则:支持开闭原则和单一职责原则。
缺点:
- 性能问题:观察者过多时,遍历通知可能导致性能瓶颈。
- 循环依赖风险:观察者间相互引用可能引发无限循环。
- 状态传递不足 :
update方法可能无法获取状态改变原因。 - 内存泄漏风险:若未正确解除引用,可能导致观察者无法回收(本实现使用智能指针避免了此问题)。
改进建议:
- 异步通知 :使用线程或事件队列实现异步
update,避免阻塞主题。 - 事件对象 :在
update方法中传递事件对象(如状态变更原因),增强信息量。 - 弱引用管理 :在主题中使用弱引用存储观察者,防止内存泄漏(本实现已用
std::shared_ptr)。 - 批量通知:对观察者分组,减少通知次数。
- 使用现有库:如 C++ Boost.Signals2 或 Qt 信号槽机制,简化实现。
观察者模式是构建灵活事件系统的核心,合理使用可大幅提升代码可维护性。