C++ 观察者模式的原理与实现
观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会收到通知并自动更新。观察者模式常用于实现发布-订阅机制,尤其在 GUI 事件系统、MVC 架构、消息推送等场景中广泛使用。
观察者模式的原理
观察者模式的核心思想是将对象之间的紧耦合关系解耦,通过建立观察者和被观察者之间的关联,使得被观察对象在状态变化时通知所有观察者,减少代码之间的依赖。
观察者模式涉及两个主要角色:
- Subject(被观察者):维护一组观察者,并在状态发生变化时通知它们。
- Observer(观察者):对被观察者的状态变化做出响应。
观察者模式的主要结构包括:
- 观察者接口:定义一个接口,使得所有观察者都可以实现
update()
方法,接收被观察者的通知。 - 被观察者类:维护一个观察者列表,并实现添加、移除观察者的方法。
- 具体观察者类:实现观察者接口,根据被观察者的通知进行更新。
观察者模式的代码实现
下面是使用 C++ 语言实现的观察者模式的详细代码示例。
1. 观察者接口
观察者接口定义了一个 update()
方法,所有观察者都需要实现这个接口。
#include <iostream>
class Observer {
public:
virtual void update() = 0; // 纯虚函数,定义接口
virtual ~Observer() {} // 虚析构函数,确保子类正确析构
};
2. 被观察者类
被观察者类 Subject
维护一个观察者列表(通常使用 std::list
来实现),并提供添加、移除观察者的方法,同时在状态变化时通知所有观察者。
#include <list>
class Subject {
private:
std::list<Observer*> observers; // 存储所有的观察者
public:
void attach(Observer* observer) {
observers.push_back(observer);
}
void detach(Observer* observer) {
observers.remove(observer);
}
void notify() {
for (Observer* observer : observers) {
observer->update(); // 通知每个观察者
}
}
};
说明:
attach()
方法用于添加观察者,detach()
方法用于移除观察者。notify()
方法遍历所有观察者,并调用其update()
方法进行通知。
3. 具体观察者类
具体观察者类实现了观察者接口,并定义如何响应被观察者的通知。
class ConcreteObserver : public Observer {
private:
std::string name;
public:
ConcreteObserver(const std::string& observerName) : name(observerName) {}
void update() override {
std::cout << "Observer " << name << " has been notified." << std::endl;
}
};
说明:
ConcreteObserver
实现了Observer
接口中的update()
方法,当被观察者通知时,打印出相应的消息。
4. 客户端代码示例
客户端代码用于测试观察者模式,创建一个被观察者和多个观察者实例,并演示它们之间的通信。
int main() {
Subject subject;
ConcreteObserver observer1("Observer1");
ConcreteObserver observer2("Observer2");
ConcreteObserver observer3("Observer3");
subject.attach(&observer1);
subject.attach(&observer2);
subject.attach(&observer3);
std::cout << "Notifying observers..." << std::endl;
subject.notify();
subject.detach(&observer2);
std::cout << "Notifying observers after detaching Observer2..." << std::endl;
subject.notify();
return 0;
}
输出结果:
Notifying observers...
Observer Observer1 has been notified.
Observer Observer2 has been notified.
Observer Observer3 has been notified.
Notifying observers after detaching Observer2...
Observer Observer1 has been notified.
Observer Observer3 has been notified.
说明:
- 创建了一个
Subject
实例和三个观察者对象,将它们注册到被观察者中。 - 调用
notify()
方法时,被观察者通知所有观察者,观察者进行响应。 - 在移除
Observer2
后再次通知,只有剩余的观察者收到通知。
观察者模式的应用场景
- GUI 事件监听:在 GUI 程序中,按钮等控件的点击操作可以通知多个监听器进行响应。
- 数据模型与视图更新:在 MVC 架构中,数据模型的变化可以通过观察者模式通知视图进行更新。
- 订阅/发布系统:在消息推送、股票市场变化等场景中,观察者模式可以实现发布者和订阅者之间的通信。
观察者模式的优缺点
优点:
- 降低耦合性:被观察者和观察者之间是抽象耦合,双方不直接依赖,符合开闭原则。
- 支持广播通信:被观察者在状态改变时可以同时通知所有观察者,实现广播效果。
缺点:
- 可能引起性能问题:如果观察者过多,通知所有观察者可能会影响性能。
- 可能引起循环依赖:在复杂系统中,观察者和被观察者之间可能会形成循环依赖,导致系统难以维护。
观察者模式的改进与多线程支持
在多线程环境中,观察者模式可能会遇到线程安全问题。为了确保线程安全,可以在被观察者中使用 std::mutex
锁来保护观察者列表,避免并发修改带来的问题。例如:
#include <mutex>
class Subject {
private:
std::list<Observer*> observers;
std::mutex mtx;
public:
void attach(Observer* observer) {
std::lock_guard<std::mutex> lock(mtx);
observers.push_back(observer);
}
void detach(Observer* observer) {
std::lock_guard<std::mutex> lock(mtx);
observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
}
void notify() {
std::lock_guard<std::mutex> lock(mtx);
for (Observer* observer : observers) {
observer->update();
}
}
};
说明:
- 使用
std::mutex
来保证对观察者列表的操作是线程安全的,避免了数据竞争和不一致的问题。
总结
观察者模式是一种非常有用的设计模式,尤其适用于一对多依赖关系的场景。它通过解耦被观察者和观察者,极大地提高了系统的灵活性和可扩展性。然而,随着系统的复杂性增加,也需要注意观察者之间可能的循环依赖问题,以及在多线程环境下的线程安全问题。
在现代 C++ 开发中,使用观察者模式可以方便地实现发布-订阅机制,为系统的模块化设计提供良好的支持。
#pragma once
#ifndef OBSERVER_H
#define OBSERVER_H
#include <iostream>
#include <list>
#include <algorithm>
#include <mutex>
// 观察者接口
class Observer {
public:
virtual void update() = 0; // 纯虚函数,定义接口
virtual ~Observer() {} // 虚析构函数,确保子类正确析构
};
// 被观察者类
class Subject {
private:
std::list<Observer*> observers; // 存储所有的观察者
std::mutex mtx; // 多线程保护
public:
// 添加观察者
void attach(Observer* observer) {
std::lock_guard<std::mutex> lock(mtx);
if (observer == NULL)
{
return;
}
auto it = observers.begin();
for (; it != observers.end(); it++)
{
if (*it == observer)
{
return;
}
}
observers.push_back(observer);
}
// 移除观察者
void detach(Observer* observer) {
std::lock_guard<std::mutex> lock(mtx);
if (observer == NULL||observers.empty()==true)
{
return;
}
observers.remove(observer);
}
// 通知所有观察者
void notify() {
std::lock_guard<std::mutex> lock(mtx);
for (Observer* observer : observers) {
observer->update(); // 通知每个观察者
}
}
};
// 具体观察者类
class ConcreteObserver : public Observer {
private:
std::string name;
public:
ConcreteObserver(const std::string& observerName) : name(observerName) {}
void update() override {
std::cout << "Observer " << name << " has been notified." << std::endl;
}
};
// 客户端代码
int main() {
Subject subject;
ConcreteObserver observer1("Observer1");
ConcreteObserver observer2("Observer2");
ConcreteObserver observer3("Observer3");
subject.attach(&observer1);
subject.attach(&observer2);
subject.attach(&observer3);
std::cout << "Notifying observers..." << std::endl;
subject.notify();
subject.detach(&observer2);
std::cout << "Notifying observers after detaching Observer2..." << std::endl;
subject.notify();
return 0;
}