深入理解观察者模式 —— Qt信号槽机制的实现

观察者模式 是一种行为型设计模式,允许一个对象(被观察者)状态发生变化时通知一组依赖它的对象(观察者),从而实现对象之间的解耦。在这篇文章中,我们将探讨如何用 C++Python 实现观察者模式,并在代码中清晰地体现这一设计模式的核心思想。

其实Qt的信号槽机制,就是借住了这一设计模式,并对其进行了一些扩展。由于Qt广泛的被C++和Python用户使用,所以这里给出Python和C++两个版本的简单实现示例。


观察者模式的核心

  1. Subject(被观察者)

    维护观察者列表并提供注册、移除和通知观察者的机制。

  2. Observer(观察者)

    定义接口,提供 update 方法,供被观察者在状态变化时调用。

  3. ConcreteObserver(具体观察者)

    实现观察者接口,响应被观察者的通知。


C++ 实现观察者模式

代码实现
cpp 复制代码
#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 实现观察者模式

代码实现
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

比较与分析

  1. C++ 和 Python 的对比

    • C++ 通过智能指针(std::shared_ptr)管理观察者生命周期,防止内存泄漏。
    • Python 利用动态特性和内置容器(如 list),代码更简洁,开发效率更高。
  2. 扩展性

    • 两种语言都可以轻松扩展为支持更复杂的通知机制,例如传递多参数、支持异步事件等。

总结

观察者模式通过将事件通知和响应解耦,为多对象之间的通信提供了一种灵活的解决方案。无论是 C++ 还是 Python,都可以方便地实现这一模式,并根据需求进行扩展。

思考

值得关注的一点,需要读者自己去尝试和实现:

  • 如何在信号槽机制中添加自定义参数
相关推荐
用户805533698035 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner5 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz10 天前
QML Hello World 入门示例
qt
xcyxiner13 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner14 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner14 天前
DicomViewer (添加模型类)3
qt
xcyxiner15 天前
DicomViewer (目录调整) 2
qt
xcyxiner15 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00617 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术17 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript