C++软件设计模式之观察者模式
观察者模式的动机意图
观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都能够自动收到通知并进行相应的更新。
动机意图:
- 解耦:观察者模式的动机在于解耦对象之间的关系。具体来说,它让一个对象(被观察者或主题)不需要知道具体有哪些对象(观察者)依赖于它,从而降低了对象之间的耦合度。
- 自动通知:当被观察者的状态发生变化时,所有观察者都会自动收到通知,并执行相应的操作。这种机制使得系统更加灵活,易于扩展和维护。
适用场合
观察者模式适用于以下场景:
- 当一个对象的状态变化需要通知其他对象,并且你不知道这些对象的具体数量和类型时。例如,图形用户界面(GUI)中的按钮点击事件,可以通知多个监听器。
- 当需要在不修改被观察者代码的情况下,动态添加或删除观察者时。这种情况下,观察者模式可以实现松耦合的设计。
- 当一个对象的状态变化会影响多个其他对象,并且这些对象需要根据状态变化自动更新时。例如,股票价格的变化会影响多个投资者的策略。
观察者模式的变体
观察者模式有几种常见的变体,具体取决于通知机制、更新方式以及观察者的管理方式。以下是几种常见的变体:
-
推模型(Push Model):
- 特点:被观察者主动将状态变化的信息推送给所有观察者。
- 优点:观察者不需要知道被观察者的内部结构,只需要处理推送过来的数据。
- 缺点:被观察者需要知道观察者的接口,可能会导致观察者和被观察者之间的耦合。
-
拉模型(Pull Model):
- 特点:被观察者仅通知观察者状态已发生变化,观察者需要主动去拉取被观察者的具体状态。
- 优点:观察者可以只拉取自己感兴趣的部分状态,减少不必要的数据传输。
- 缺点:观察者需要了解被观察者的内部结构。
-
事件机制(Event-based Model):
- 特点:被观察者通过事件通知观察者,观察者可以订阅特定类型的事件。
- 优点:可以处理更复杂的事件类型,支持多种事件的订阅和处理。
- 缺点:实现复杂度较高。
-
观察者队列(Observer Queue):
- 特点:使用队列来管理观察者,当被观察者状态变化时,将通知放入队列中,观察者从队列中取出通知进行处理。
- 优点:可以实现异步通知,提高系统的并发性能。
- 缺点:可能引入额外的复杂性和延迟。
-
弱引用观察者(Weak Reference Observer):
- 特点:使用弱引用(Weak Reference)来管理观察者,防止观察者对象未被释放时导致的内存泄漏。
- 优点:可以避免内存泄漏问题。
- 缺点:需要额外的机制来管理弱引用。
总结
观察者模式通过解耦对象之间的关系,提供了一种灵活且易于扩展的通知机制。它的变体如推模型、拉模型、事件机制等,使得它在不同的场景中可以有不同的实现方式。基于观察者模式的特点,发布-订阅模式、事件驱动架构、MVC模式等软件架构模式在现代软件开发中得到了广泛的应用。这些架构模式不仅提高了系统的灵活性和可维护性,还使得系统在面对变化时能够更加从容应对。
下面是观察者模式的不同变体的C++代码示例,包括推模型、拉模型、事件机制、观察者队列和弱引用观察者。
1. 推模型(Push Model)
在推模型中,被观察者将状态变化的信息主动推送给所有观察者。
示例代码
#include <iostream>
#include <vector>
#include <string>
// 观察者接口
class Observer {
public:
virtual void update(const std::string& message) = 0;
virtual ~Observer() = default;
};
// 具体观察者
class ConcreteObserver : public Observer {
public:
void update(const std::string& message) override {
std::cout << "Observer received message: " << message << std::endl;
}
};
// 被观察者接口
class Subject {
public:
virtual void attach(Observer* observer) = 0;
virtual void detach(Observer* observer) = 0;
virtual void notify(const std::string& message) = 0;
virtual ~Subject() = default;
};
// 具体被观察者
class ConcreteSubject : public Subject {
private:
std::vector<Observer*> observers;
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(const std::string& message) override {
for (Observer* observer : observers) {
observer->update(message);
}
}
void changeState(const std::string& message) {
std::cout << "Subject state changed. Notifying observers..." << std::endl;
notify(message);
}
};
int main() {
ConcreteSubject subject;
ConcreteObserver observer1;
ConcreteObserver observer2;
subject.attach(&observer1);
subject.attach(&observer2);
subject.changeState("Hello Observers!");
subject.detach(&observer1);
subject.changeState("Hello again!");
return 0;
}
2. 拉模型(Pull Model)
在拉模型中,被观察者仅通知观察者状态已发生变化,观察者需要主动去拉取被观察者的具体状态。
示例代码
#include <iostream>
#include <vector>
#include <string>
// 被观察者接口
class Subject {
public:
virtual std::string getState() const = 0;
virtual void notify() = 0;
virtual void setState(const std::string& state) = 0;
virtual void attach(class Observer* observer) = 0;
virtual void detach(class Observer* observer) = 0;
virtual ~Subject() = default;
};
// 具体被观察者
class ConcreteSubject : public Subject {
private:
std::string state;
std::vector<class Observer*> observers;
public:
std::string getState() const override {
return state;
}
void setState(const std::string& state) override {
this->state = state;
notify();
}
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 (Observer* observer : observers) {
observer->update();
}
}
};
// 观察者接口
class Observer {
protected:
Subject* subject;
public:
Observer(Subject* subject) : subject(subject) {}
virtual void update() = 0;
virtual ~Observer() = default;
};
// 具体观察者
class ConcreteObserver : public Observer {
public:
ConcreteObserver(Subject* subject) : Observer(subject) {}
void update() override {
std::string state = subject->getState();
std::cout << "Observer received state: " << state << std::endl;
}
};
int main() {
ConcreteSubject subject;
ConcreteObserver observer1(&subject);
ConcreteObserver observer2(&subject);
subject.attach(&observer1);
subject.attach(&observer2);
subject.setState("State 1");
subject.detach(&observer1);
subject.setState("State 2");
return 0;
}
3. 事件机制(Event-based Model)
在事件机制中,被观察者通过事件通知观察者,观察者可以订阅特定类型的事件。
示例代码
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <functional>
// 事件类型
enum class EventType {
StateChanged,
DataUpdated
};
// 事件
class Event {
public:
EventType type;
std::string data;
Event(EventType type, const std::string& data) : type(type), data(data) {}
};
// 观察者接口
class Observer {
public:
virtual void handleEvent(const Event& event) = 0;
virtual ~Observer() = default;
};
// 具体观察者
class ConcreteObserver : public Observer {
public:
void handleEvent(const Event& event) override {
std::cout << "Observer received event of type: " << static_cast<int>(event.type)
<< " with data: " << event.data << std::endl;
}
};
// 被观察者接口
class Subject {
private:
std::map<EventType, std::vector<Observer*>> eventObservers;
public:
void attach(EventType type, Observer* observer) {
eventObservers[type].push_back(observer);
}
void detach(EventType type, Observer* observer) {
auto& observers = eventObservers[type];
observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
}
void notify(const Event& event) {
auto& observers = eventObservers[event.type];
for (Observer* observer : observers) {
observer->handleEvent(event);
}
}
void changeState(const std::string& state) {
std::cout << "Subject state changed." << std::endl;
notify(Event(EventType::StateChanged, state));
}
void updateData(const std::string& data) {
std::cout << "Subject data updated." << std::endl;
notify(Event(EventType::DataUpdated, data));
}
};
int main() {
Subject subject;
ConcreteObserver observer1;
ConcreteObserver observer2;
subject.attach(EventType::StateChanged, &observer1);
subject.attach(EventType::DataUpdated, &observer2);
subject.changeState("New State");
subject.updateData("New Data");
subject.detach(EventType::StateChanged, &observer1);
subject.changeState("Another State");
return 0;
}
4. 观察者队列(Observer Queue)
在观察者队列中,使用队列来管理观察者,当被观察者状态变化时,将通知放入队列中,观察者从队列中取出通知进行处理。
示例代码
#include <iostream>
#include <queue>
#include <string>
#include <mutex>
#include <thread>
#include <condition_variable>
// 通知类型
class Notification {
public:
virtual void process() = 0;
virtual ~Notification() = default;
};
// 具体通知
class ConcreteNotification : public Notification {
private:
std::string message;
public:
ConcreteNotification(const std::string& message) : message(message) {}
void process() override {
std::cout << "Processing notification: " << message << std::endl;
}
};
// 观察者队列
class ObserverQueue {
private:
std::queue<Notification*> queue;
std::mutex mutex;
std::condition_variable cv;
public:
void enqueue(Notification* notification) {
std::lock_guard<std::mutex> lock(mutex);
queue.push(notification);
cv.notify_one();
}
void processQueue() {
while (true) {
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock, [this] { return !queue.empty(); });
Notification* notification = queue.front();
queue.pop();
lock.unlock();
notification->process();
delete notification;
}
}
};
int main() {
ObserverQueue queue;
std::thread worker([&queue]() { queue.processQueue(); });
queue.enqueue(new ConcreteNotification("Notification 1"));
queue.enqueue(new ConcreteNotification("Notification 2"));
queue.enqueue(new ConcreteNotification("Notification 3"));
worker.join();
return 0;
}
5. 弱引用观察者(Weak Reference Observer)
在弱引用观察者中,使用弱引用(Weak Reference)来管理观察者,防止观察者对象未被释放时导致的内存泄漏。
示例代码
#include <iostream>
#include <vector>
#include <memory>
#include <string>
#include <functional>
// 观察者接口
class Observer {
public:
virtual void update(const std::string& message) = 0;
virtual ~Observer() = default;
};
// 具体观察者
class ConcreteObserver : public Observer {
public:
void update(const std::string& message) override {
std::cout << "Observer received message: " << message << std::endl;
}
};
// 被观察者接口
class Subject {
public:
virtual void attach(std::weak_ptr<Observer> observer) = 0;
virtual void notify(const std::string& message) = 0;
virtual ~Subject() = default;
};
// 具体被观察者
class ConcreteSubject : public Subject {
private:
std::vector<std::weak_ptr<Observer>> observers;
public:
void attach(std::weak_ptr<Observer> observer) override {
observers.push_back(observer);
}
void notify(const std::string& message) override {
observers.erase(std::remove_if(observers.begin(), observers.end(),
[](const std::weak_ptr<Observer>& observer) {
return observer.expired();
}), observers.end());
for (auto& observer : observers) {
if (auto sharedObserver = observer.lock()) {
sharedObserver->update(message);
}
}
}
void changeState(const std::string& message) {
std::cout << "Subject state changed. Notifying observers..." << std::endl;
notify(message);
}
};
int main() {
ConcreteSubject subject;
auto observer1 = std::make_shared<ConcreteObserver>();
auto observer2 = std::make_shared<ConcreteObserver>();
subject.attach(observer1);
subject.attach(observer2);
subject.changeState("Hello Observers!");
observer1.reset(); // 释放 observer1
subject.changeState("Hello again!");
return 0;
}
总结
以上是观察者模式的几种不同变体的C++代码示例。每种变体都有其适用的场景和优缺点,开发者可以根据具体的需求选择合适的实现方式。观察者模式的核心思想是解耦对象之间的关系,并通过通知机制实现对象之间的通信。
基于观察者模式特点的软件架构模式
观察者模式的特性使得它在许多软件架构中都有重要的应用,以下是几种基于观察者模式特点的软件架构模式:
-
发布-订阅模式(Publish-Subscribe Pattern):
- 特点:发布-订阅模式是观察者模式的一种扩展,它将消息的发送者(发布者)和接收者(订阅者)完全解耦。发布者不需要知道订阅者的存在,订阅者也不需要知道发布者的存在。
- 应用:常见的应用场景包括消息队列系统(如 Kafka、RabbitMQ)、事件驱动系统等。
- 优点:系统组件之间的耦合度极低,适合构建分布式系统。
-
事件驱动架构(Event-Driven Architecture):
- 特点:事件驱动架构是一种基于事件的架构模式,系统中的组件通过事件进行通信。事件的产生和处理通常基于观察者模式。
- 应用:常见的应用场景包括图形用户界面、分布式系统、微服务架构等。
- 优点:系统组件可以异步处理事件,提高系统的可扩展性和响应性。
-
模型-视图-控制器(MVC)模式:
- 特点:MVC模式将应用程序分为三个部分:模型(Model)、视图(View)和控制器(Controller)。模型是观察者模式中的被观察者,视图是观察者。当模型的状态发生变化时,视图会自动更新。
- 应用:常见的应用场景包括Web应用程序、桌面应用程序等。
- 优点:模型和视图之间的解耦,使得系统更易于维护和扩展。
-
观察者-被观察者链(Observer-Observable Chain):
- 特点:在这种架构中,观察者和被观察者可以形成一个链式结构,每个被观察者可以同时是观察者。
- 应用:常见的应用场景包括事件传播链、责任链模式等。
- 优点:可以实现复杂的事件传播和处理机制。
原文地址:https://blog.csdn.net/joshua0137/article/details/144810980
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!