简介
观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,使得当一个对象的状态发生变化时,所有依赖它的对象都能够自动收到通知并更新。
描述
观察者模式由两个核心件组成:主题(Subject)和观察者(Observer)。主题是一个可被观察的对象,它维护了一个观察者列表,可以动态地添加、删除和通知观察者。观察者是依赖于主题的对象,当主题发生变化时,观察者会自动更新自己的状态。
原理
观察者模式通过定义了主题和观察者之间的接口,使得主题和观察者可以彼此独立地进行交互。当主题的状态发生变化时,它会通知所有的观察者,而观察者会根据主题的通知进行相应的更新。
类图
Subject:目标类,它是一个抽象类,也是所有目标对象的父类。它用一个列表记录当前目标对象有哪些观察者对象,并提供增加、删除观察者对象和通知观察者对象的接口。
Observer:观察者类,它也是一个抽象类,是所有观察者对象的父类;它为所有的观察者对象都定义了一个名为update的方法(也叫成员函数)。当目标对象的状态改变时,它就是通过调用它的所有观察者对象的update方法来通知它们的。
ConcreteSubject:具体目标类,可以有多个不同的具体目标类,它们同时继承Subject类。一个目标对象就是某个具体目标类的对象,一个具体目标类负责定义它自身的事务逻辑,并在状态改变时通知它的所有观察者对象。
ConcreteObserver:具体观察者类,可以有多个不同的具体观察者类,它们同时继承Observer类。一个观察者对象就是某个具体观察者类的对象。每个具体观察者类都要重定义Observer类中定义的update方法,在该方法中实现它自己的任务逻辑,当它被通知的时候(目标对象调用它的update方法)就执行自己特有的任务。
示例
假设有一个天气预报系统,其中天气数据是主题,用户界面、手机App电视等是观察者。当天气数据更新时,所有的观察者都能够收到通知并更新自己的内容。
C++示例代码如下:
#include <iostream>
#include <vector>
// 主题接口
class Subject {
public:
virtual void attach(Observer* observer) = 0;
virtual void detach(Observer* observer) = 0;
virtual void notify() = 0;
};
// 观察者接口
class Observer {
public:
virtual void update(const std::string& message) = 0;
};
// 具体主题
class WeatherData : public Subject {
public:
void attach(Observer* observer) override {
observers.push_back(observer);
}
void detach(Observer* observer) override {
for (auto it = observers.begin(); it != observers.end(); ++it) {
if (*it == observer) {
observers.erase(it);
break;
}
}
}
void notify() override {
for (Observer* observer : observers) {
observer->update(message);
}
}
void setMessage(const std::string& message) {
this->message = message;
notify();
}
private:
std::vector<Observer*> observers;
std::string message;
};
// 具体观察者
class UserInterface : public Observer {
public:
void update(const std::string& message override {
std::cout << "User Interface: " << message << std::endl;
}
};
class MobileApp : public Observer {
public:
void update(const std::string& message) override {
std::cout << "Mobile App: " << message << std::endl;
}
};
class TV : public Observer {
public:
void update(const std::string& message) override {
std::cout << "TV: " << message << std::endl;
}
};
// 使用示例
int main() {
WeatherData weatherData;
UserInterface userInterface;
MobileApp mobileApp;
TV tv;
weatherData.attach(&userInterface);
weatherData.attach(&mobileApp);
weatherData.attach(&tv);
weatherData.setMessage("The is sunny.");
weatherData.detach(&mobileApp);
weatherData.setMessage("The weather is rainy");
return 0;
}
输出结果
User Interface: The weather is sunny.
Mobile App: The weather is sunny.
TV: The is sunny.
User Interface: The weather is rainy.
TV: The weather is rainy.
解释
在上述示例中,主题接口(Subject)定义了操作观察者的方法,包括添加观察者、删除观察者和通知观察者。
具体主题(WeatherData)实现了主题接口,并维护了一个观察者列表。
观察者接口(Observer)定义了观察者的更新方法,具体观察者(UserInterface、MobileApp、TV)实现了观察者接口,并根据主题的通知进行相应的更新。
在示例中,创建了一个天气数据对象(WeatherData)作为主题,然后创建了三个观察者(UserInterface、MobileApp、TV)。将观察者添加到天气数据对象的观察者列表中,然后模拟天气数据发生变化,通过调用主题的notify方法通知所有的观察者。察者接收到通知后,会调用自己的update方法进行相应的更新操作。
结论
结论观察者模式通过定义了一种一对多的依赖关系,使得主题和观察者之间能够彼此独立地进行交互。它实现了对象间的解耦,当一个对象的状态发生变化时,所有依赖它的对象都能够自动收到通知并进行相的更新。
观察者模式适用场景:
- 当一个对象的改变需要同时通知其他对象,并且不道具体有多少个对象需要通知时,可以使用观察者模式实现松散的耦合。
- 当一个对象需要将自己的改变通知给其他对象,但是又希望避免耦合时,可以使用观察者模式。
观察者模式常见的应用场景包括事件驱动系统、GUI界面组件、消息队列系统等。