深入理解观察者模式 —— Qt信号槽机制的实现
观察者模式是一种行为型设计模式,允许一个对象(被观察者)状态发生变化时通知一组依赖它的对象(观察者),从而实现对象之间的解耦。在这篇文章中,我们将探讨如何用 C++ 和 Python 实现观察者模式,并在代码中清晰地体现这一设计模式的核心思想。
其实Qt的信号槽机制,就是借住了这一设计模式,并对其进行了一些扩展。由于Qt广泛的被C++和Python用户使用,所以这里给出Python和C++两个版本的简单实现示例。
观察者模式的核心
-
Subject(被观察者)
维护观察者列表并提供注册、移除和通知观察者的机制。 -
Observer(观察者)
定义接口,提供update
方法,供被观察者在状态变化时调用。 -
ConcreteObserver(具体观察者)
实现观察者接口,响应被观察者的通知。
C++ 实现观察者模式
代码实现
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
// 抽象观察者接口
class Observer {
public:
virtual ~Observer() = default;
virtual void update(const std::string& message) = 0;
};
// 被观察者类
class Subject {
public:
void attach(const std::shared_ptr<Observer>& observer) {
m_observers.push_back(observer);
}
void detach(const std::shared_ptr<Observer>& observer) {
m_observers.erase(
std::remove(m_observers.begin(), m_observers.end(), observer),
m_observers.end()
);
}
void notify(const std::string& message) {
for (const auto& observer : m_observers) {
if (observer) {
observer->update(message);
}
}
}
private:
std::vector<std::shared_ptr<Observer>> m_observers; // 观察者列表
};
// 具体观察者
class ConcreteObserver : public Observer {
public:
explicit ConcreteObserver(const std::string& name) : m_name(name) {}
void update(const std::string& message) override {
std::cout << "Observer [" << m_name << "] received message: " << message << std::endl;
}
private:
std::string m_name; // 观察者名称
};
int main() {
// 创建被观察者
Subject subject;
// 创建具体观察者
auto observer1 = std::make_shared<ConcreteObserver>("Observer1");
auto observer2 = std::make_shared<ConcreteObserver>("Observer2");
// 注册观察者
subject.attach(observer1);
subject.attach(observer2);
// 通知所有观察者
std::cout << "Sending notification: 'Event A occurred'" << std::endl;
subject.notify("Event A occurred");
// 移除一个观察者
subject.detach(observer1);
// 再次通知
std::cout << "Sending notification: 'Event B occurred'" << std::endl;
subject.notify("Event B occurred");
return 0;
}
输出结果
Sending notification: 'Event A occurred'
Observer [Observer1] received message: Event A occurred
Observer [Observer2] received message: Event A occurred
Sending notification: 'Event B occurred'
Observer [Observer2] received message: Event B occurred
Python 实现观察者模式
代码实现
from typing import List
# 抽象观察者接口
class Observer:
def update(self, message: str):
"""被通知时调用的方法"""
raise NotImplementedError("Subclass must implement abstract method")
# 被观察者类
class Subject:
def __init__(self):
self._observers: List[Observer] = [] # 观察者列表
def attach(self, observer: Observer):
"""注册观察者"""
if observer not in self._observers:
self._observers.append(observer)
def detach(self, observer: Observer):
"""移除观察者"""
if observer in self._observers:
self._observers.remove(observer)
def notify(self, message: str):
"""通知所有观察者"""
for observer in self._observers:
observer.update(message)
# 具体观察者
class ConcreteObserver(Observer):
def __init__(self, name: str):
self._name = name
def update(self, message: str):
print(f"Observer {self._name} received message: {message}")
# 测试代码
if __name__ == "__main__":
# 创建被观察者
subject = Subject()
# 创建具体观察者
observer1 = ConcreteObserver("Observer1")
observer2 = ConcreteObserver("Observer2")
# 注册观察者
subject.attach(observer1)
subject.attach(observer2)
# 通知所有观察者
print("Sending notification: 'Event A occurred'")
subject.notify("Event A occurred")
# 移除一个观察者
subject.detach(observer1)
# 再次通知
print("Sending notification: 'Event B occurred'")
subject.notify("Event B occurred")
输出结果
Sending notification: 'Event A occurred'
Observer Observer1 received message: Event A occurred
Observer Observer2 received message: Event A occurred
Sending notification: 'Event B occurred'
Observer Observer2 received message: Event B occurred
比较与分析
-
C++ 和 Python 的对比
- C++ 通过智能指针(
std::shared_ptr
)管理观察者生命周期,防止内存泄漏。 - Python 利用动态特性和内置容器(如
list
),代码更简洁,开发效率更高。
- C++ 通过智能指针(
-
扩展性
- 两种语言都可以轻松扩展为支持更复杂的通知机制,例如传递多参数、支持异步事件等。
总结
观察者模式通过将事件通知和响应解耦,为多对象之间的通信提供了一种灵活的解决方案。无论是 C++ 还是 Python,都可以方便地实现这一模式,并根据需求进行扩展。
思考
值得关注的一点,需要读者自己去尝试和实现:
- 如何在信号槽机制中添加自定义参数