1. 观察者模式 (Observer Pattern)
这是最直接、最经典的解决方案,也是Qt信号/槽机制的理论基础。
核心思想: 定义一种一对多的依赖关系,当一个对象(Subject,主题)的状态发生改变时,所有依赖于它的对象(Observers,观察者)都会得到通知并自动更新。
实现方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
| #include <iostream> #include <vector> #include <algorithm> #include <memory>
class Observer;
class Subject { public: virtual ~Subject() = default; virtual void attach(std::weak_ptr<Observer> observer) = 0; virtual void detach(std::weak_ptr<Observer> observer) = 0; virtual void notify() = 0; };
class Observer { public: virtual ~Observer() = default; virtual void update() = 0; };
class ConcreteSubject : public Subject, public std::enable_shared_from_this<ConcreteSubject> { public: void doWork() { std::cout << "Working..." << std::endl; std::cout << "Work done! Notifying observers." << std::endl; notify(); }
void attach(std::weak_ptr<Observer> observer) override { observers_.push_back(observer); }
void detach(std::weak_ptr<Observer> observer) override { observers_.erase( std::remove_if(observers_.begin(), observers_.end(), [&observer](const std::weak_ptr<Observer>& wp) { return wp.lock() == observer.lock(); }), observers_.end()); }
void notify() override { for (auto it = observers_.begin(); it != observers_.end(); ) { if (auto obs = it->lock()) { obs->update(); ++it; } else { it = observers_.erase(it); } } }
private: std::vector<std::weak_ptr<Observer>> observers_; };
class ConcreteObserver : public Observer, public std::enable_shared_from_this<ConcreteObserver> { public: ConcreteObserver(const std::string& name) : name_(name) {}
void update() override { std::cout << "Observer " << name_ << ": Received update! Updating UI..." << std::endl; }
void subscribeTo(const std::shared_ptr<Subject>& subject) { subject_ = subject; subject_->attach(std::weak_ptr<Observer>(shared_from_this())); }
void unsubscribe() { if (auto sub = subject_.lock()) { sub->detach(std::weak_ptr<Observer>(shared_from_this())); } }
private: std::string name_; std::weak_ptr<Subject> subject_; };
int main() { auto worker = std::make_shared<ConcreteSubject>(); auto uiUpdater1 = std::make_shared<ConcreteObserver>("UI 1"); auto uiUpdater2 = std::make_shared<ConcreteObserver>("UI 2");
uiUpdater1->subscribeTo(worker); uiUpdater2->subscribeTo(worker);
worker->doWork();
uiUpdater1->unsubscribe(); std::cout << "\n--- After unsubscribe ---\n"; worker->doWork();
return 0; }
|
优点: 实现了松耦合,Subject不需要知道Observer的具体细节。
缺点: 需要自己管理Observer的注册、注销和生命周期(使用std::weak_ptr
防止悬挂指针)。
2. 回调函数 (Callbacks) / 函数对象 (Function Objects / std::function)
这是一种更轻量级的方式,特别适合一对一的通信场景。
实现方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| #include <iostream> #include <functional> #include <vector>
class Worker { public: using Callback = std::function<void(int result)>;
void setCompletionCallback(const Callback& cb) { completionCallback_ = cb; }
void addProgressCallback(const Callback& cb) { progressCallbacks_.push_back(cb); }
void doWork() { for (int i = 0; i <= 100; i += 25) { std::cout << "Progress: " << i << "%" << std::endl; for (const auto& cb : progressCallbacks_) { if (cb) cb(i); } } if (completionCallback_) { completionCallback_(42); } }
private: Callback completionCallback_; std::vector<Callback> progressCallbacks_; };
class UI { public: void updateProgress(int value) { std::cout << "UI: Updating progress bar to " << value << "%" << std::endl; }
void handleResult(int result) { std::cout << "UI: Got result: " << result << std::endl; } };
int main() { Worker worker; UI ui;
worker.setCompletionCallback([&ui](int result) { ui.handleResult(result); }); worker.addProgressCallback([&ui](int progress) { ui.updateProgress(progress); });
worker.addProgressCallback([](int progress) { std::cout << "Logger: Progress is " << progress << "%" << std::endl; });
worker.doWork();
return 0; }
|
优点: 非常灵活,语法简单,C++11及以上标准支持良好。
缺点: 一对多需要自己管理回调列表。要非常小心回调函数和对象的生命周期(上面的例子使用了lambda捕获引用&ui
,如果ui
先于worker
被销毁,就会导致未定义行为)。
3. 基于事件的系统 (Event Bus)
这是一个更高级、更通用的模式,常用于大型应用程序,它本身是一个中央调度器。
简化实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| #include <iostream> #include <map> #include <vector> #include <functional> #include <memory> #include <string>
struct Event { virtual ~Event() = default; };
struct WorkCompletedEvent : public Event { int result; WorkCompletedEvent(int r) : result(r) {} };
struct ProgressUpdatedEvent : public Event { int progress; ProgressUpdatedEvent(int p) : progress(p) {} };
class EventBus { public: using Subscriber = std::function<void(const Event&)>;
template <typename EventType> void subscribe(Subscriber subscriber) { subscribers_[typeid(EventType).name()].push_back(subscriber); }
template <typename EventType> void publish(const EventType& event) { auto it = subscribers_.find(typeid(EventType).name()); if (it != subscribers_.end()) { for (const auto& subscriber : it->second) { subscriber(event); } } }
private: std::map<std::string, std::vector<Subscriber>> subscribers_; };
int main() { EventBus bus;
Worker worker(bus); UI ui(bus);
bus.subscribe<ProgressUpdatedEvent>([](const Event& e) { const auto& event = static_cast<const ProgressUpdatedEvent&>(e); std::cout << "UI Event: Progress " << event.progress << "%" << std::endl; });
bus.subscribe<WorkCompletedEvent>([](const Event& e) { const auto& event = static_cast<const WorkCompletedEvent&>(e); std::cout << "UI Event: Result " << event.result << std::endl; });
return 0; }
|
优点: 极度松耦合,组件之间通过事件通信,完全不知道对方的存在。非常灵活和强大。
缺点: 实现相对复杂,调试可能更困难(事件流不直观)。
总结:纯C++的解决方案
方法 |
适用场景 |
优点 |
缺点 |
观察者模式 |
经典的一对多通知,结构清晰 |
松耦合,意图明确 |
需要自己实现和管理,代码量稍大 |
回调函数 (std::function ) |
轻量级,一对一或简单一对多 |
灵活,简单,现代C++标准支持 |
生命周期管理需谨慎,一对多需自行维护列表 |
事件总线 (Event Bus) |
大型应用,复杂组件间通信 |
极度松耦合,高度灵活 |
实现复杂,系统行为不易跟踪,调试难 |
Qt的信号/槽机制可以看作是这些模式的一个集大成者:
它提供了观察者模式的清晰结构,用起来像回调函数一样简单直观,并且通过元对象系统实现了比手动事件总线更强大、更安全、更易用的功能。