观察者模式 (Observer)
观察者模式 是一种行为型设计模式,它定义了一种一对多的依赖关系,使得当一个对象的状态发生改变时,其依赖者(观察者)会收到通知并自动更新。
意图
- 定义对象之间的一对多依赖关系。
- 当一个对象状态发生变化时,通知所有依赖于它的对象。
使用场景
-
事件驱动系统:
- 如 GUI 程序中的按钮点击事件,按钮通知所有监听器。
-
数据变化通知:
- 数据模型的变化需要通知多个视图更新。
-
解耦对象之间的依赖:
- 被观察者与观察者通过接口交互,降低了耦合性。
参与者角色
-
主题 (Subject)
- 被观察者,维护观察者列表,并在状态发生变化时通知所有观察者。
-
观察者 (Observer)
- 定义了一个接口,用于接收通知并更新状态。
-
具体主题 (ConcreteSubject)
- 实现具体的主题逻辑,存储状态,并在状态改变时通知观察者。
-
具体观察者 (ConcreteObserver)
- 实现具体的观察者逻辑,接收通知并更新状态。
示例代码
以下代码展示了观察者模式的实现,使用 C++ 的现代特性(如 std::function
、std::vector
、shared_ptr
)。
cpp
#include <iostream>
#include <vector>
#include <memory>
#include <functional>
#include <string>
// 观察者接口
class Observer {
public:
virtual ~Observer() = default;
virtual void update(const std::string& message) = 0; // 接收通知
};
// 具体观察者:实现观察者接口
class ConcreteObserver : public Observer {
private:
std::string name; // 观察者名称,用于标识
public:
explicit ConcreteObserver(const std::string& observerName) : name(observerName) {}
void update(const std::string& message) override {
std::cout << "观察者 [" << name << "] 收到通知: " << message << std::endl;
}
};
// 被观察者接口
class Subject {
public:
virtual ~Subject() = default;
virtual void attach(std::shared_ptr<Observer> observer) = 0; // 添加观察者
virtual void detach(std::shared_ptr<Observer> observer) = 0; // 移除观察者
virtual void notify() = 0; // 通知观察者
};
// 具体被观察者:实现被观察者接口
class ConcreteSubject : public Subject {
private:
std::vector<std::shared_ptr<Observer>> observers; // 存储观察者的列表
std::string state; // 被观察者的状态
public:
void attach(std::shared_ptr<Observer> observer) override {
observers.push_back(observer);
}
void detach(std::shared_ptr<Observer> observer) override {
observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
}
void setState(const std::string& newState) {
state = newState;
notify(); // 状态改变时通知所有观察者
}
void notify() override {
for (const auto& observer : observers) {
observer->update(state);
}
}
};
// 客户端代码
int main() {
auto subject = std::make_shared<ConcreteSubject>();
// 创建多个观察者
auto observer1 = std::make_shared<ConcreteObserver>("Observer1");
auto observer2 = std::make_shared<ConcreteObserver>("Observer2");
auto observer3 = std::make_shared<ConcreteObserver>("Observer3");
// 观察者订阅被观察者
subject->attach(observer1);
subject->attach(observer2);
subject->attach(observer3);
// 修改被观察者的状态,通知观察者
std::cout << "修改状态为: 状态A" << std::endl;
subject->setState("状态A");
// 移除一个观察者
subject->detach(observer2);
std::cout << "修改状态为: 状态B" << std::endl;
subject->setState("状态B");
return 0;
}
代码解析
1. 观察者接口 (Observer)
- 定义了一个
update
方法,用于接收通知:
cpp
class Observer {
public:
virtual ~Observer() = default;
virtual void update(const std::string& message) = 0; // 接收通知
};
2. 具体观察者 (ConcreteObserver)
- 实现了
Observer
接口,并通过update
方法更新状态:
cpp
class ConcreteObserver : public Observer {
private:
std::string name;
public:
explicit ConcreteObserver(const std::string& observerName) : name(observerName) {}
void update(const std::string& message) override {
std::cout << "观察者 [" << name << "] 收到通知: " << message << std::endl;
}
};
3. 被观察者接口 (Subject)
- 定义了添加、移除观察者的方法,以及通知观察者的
notify
方法:
cpp
class Subject {
public:
virtual ~Subject() = default;
virtual void attach(std::shared_ptr<Observer> observer) = 0;
virtual void detach(std::shared_ptr<Observer> observer) = 0;
virtual void notify() = 0;
};
4. 具体被观察者 (ConcreteSubject)
- 存储观察者列表,并在状态改变时通知观察者:
cpp
class ConcreteSubject : public Subject {
private:
std::vector<std::shared_ptr<Observer>> observers;
std::string state;
public:
void setState(const std::string& newState) {
state = newState;
notify(); // 状态改变时通知所有观察者
}
void notify() override {
for (const auto& observer : observers) {
observer->update(state);
}
}
};
5. 客户端
- 客户端通过
attach
方法订阅观察者,并通过setState
方法触发通知:
cpp
auto subject = std::make_shared<ConcreteSubject>();
auto observer1 = std::make_shared<ConcreteObserver>("Observer1");
subject->attach(observer1);
subject->setState("状态A");
优缺点
优点
- 解耦 :
- 被观察者与观察者之间通过接口交互,降低了依赖性。
- 扩展性强 :
- 可以轻松增加新的观察者,而无需修改被观察者代码。
- 动态通知 :
- 可以在运行时动态添加或移除观察者。
缺点
- 通知开销 :
- 当观察者较多时,通知的开销可能较大。
- 复杂性增加 :
- 系统中对象关系变得复杂,可能导致调试困难。
适用场景
-
事件驱动系统:
- 如 GUI 程序、游戏引擎等。
-
模型-视图结构:
- 数据模型的变化通知视图更新。
-
分布式系统:
- 如多个服务监听同一个事件源。
总结
观察者模式通过定义一对多的依赖关系,解决了对象之间的动态联动问题,是事件驱动系统中非常重要的设计模式。