一.观察者模式
观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象,当主题对象状态发生改变时,会通知所有观察者对象,使它们自动更新自己。
1.作用
观察者模式的主要作用在于解耦观察者和被观察者,使它们之间的依赖关系变得松散,从而提高系统的可扩展性和可维护性。观察者模式还有以下的作用:
- 支持广播通信:当一个对象发生改变时,所有依赖于它的对象都会收到通知,这样就可以实现对象间的广播通信。
- 提供面向对象设计的基础:观察者模式将观察者和被观察者之间的关系抽象化,使得它们可以独立地变化,从而更好地支持面向对象设计的原则。
- 降低系统的耦合度:观察者模式可以将观察者和被观察者之间的依赖关系解耦,从而降低系统的耦合度,使得系统更加灵活、可扩展和可维护。
- 支持事件驱动编程:观察者模式可以将事件的发布和订阅抽象化,从而支持事件驱动编程,这在GUI编程、网络编程等领域中非常常见。
2.适用场景
观察者模式适用于那些需要解耦观察者和被观察者之间的依赖关系,同时需要实现多个对象之间的通信和协作的场景。
- GUI(图形用户界面)开发:在 GUI 应用程序中,我们经常需要更新多个 UI控件的状态,以响应用户输入或其他操作。这些控件可能来自不同的类,但它们需要共享某些数据。这时候,我们可以使用观察者模式来解耦控件之间的依赖关系。
- 网络编程:在分布式系统中,通常需要处理大量的网络事件和消息,例如客户端连接、断开、数据传输等。这时候,我们可以使用观察者模式来简化事件和消息的处理。
- 日志记录:在大型应用程序中,日志记录是必不可少的。观察者模式可以让我们将日志记录器与日志处理器解耦,从而提高代码的可维护性和扩展性。
- 数据库设计:在数据库设计中,我们可以使用观察者模式来实现触发器(trigger)的功能。触发器可以在数据库中的某个表发生变化时自动触发一些操作,例如更新其他表的数据、发送邮件通知。
- 事件驱动编程:在事件驱动编程中,我们可以使用观察者模式来实现事件的注册和处理。事件可以是用户输入、硬件事件、系统消息等。当事件发生时,观察者模式可以自动通知所有的事件处理器进行处理。
3.实现要素
- Subject——抽象主题(抽象被观察者):抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
- ConcreteSubject——具体主题(具体被观察者):该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
- Observer——抽象观察者:是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
- ConcrereObserver——具体观察者:实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。
二.C++程序示例
#include <iostream>
#include <vector>
class Observer { // 抽象观察者
public:
virtual void update() = 0;
};
class Subject { // 抽象主题
public:
virtual void attach(Observer* observer) = 0;
virtual void detach(Observer* observer) = 0;
virtual void notify() = 0;
};
class Cart : public Subject { // 具体主题
private:
std::vector<Observer*> observers;
int totalPrice;
public:
void attach(Observer* observer) override {
observers.push_back(observer);
}
void detach(Observer* observer) override {
observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
}
void notify() override {
for (auto observer : observers) {
observer->update();
}
}
void setTotalPrice(int price) {
totalPrice = price;
notify();
}
int getTotalPrice() const {
return totalPrice;
}
};
class Customer : public Observer { // 具体观察者
private:
std::string name;
Cart* cart;
public:
Customer(std::string name, Cart* cart) : name(name), cart(cart) {}
void update() override {
std::cout << name << " receives the updated cart total price: $" << cart->getTotalPrice() << std::endl;
}
};
int main() {
Cart* cart = new Cart();
Customer* customer1 = new Customer("Alice", cart);
Customer* customer2 = new Customer("Bob", cart);
cart->attach(customer1);
cart->attach(customer2);
cart->setTotalPrice(100);
cart->detach(customer2);
cart->setTotalPrice(200);
delete cart;
delete customer1;
delete customer2;
return 0;
}
Subject 抽象主题,定义了增加、删除观察者和通知观察者的接口。
Cart 具体主题,实现了抽象主题的接口,维护了一个观察者列表,以及具体状态。
Observer 抽象观察者,定义了一个更新接口。
Customer 具体观察者,实现了抽象观察者的接口,持有具体主题的引用,在状态改变时接收通知并做出相应的响应。
在 main 函数中创建具体主题和具体观察者对象,并对其进行操作,以此演示观察者模式的工作方式。