用观察者模式用UI显示数据变化
#include "QtWidgetsApplication1.h"
#include <QtWidgets/QApplication>
#include "Observer.h"
#include <QDebug>class UIObserver : public Observer {
public:void Execute() override { qDebug() << "[UI] refresh"; }
};class IoObserver : public Observer {
public:void Execute() override{qDebug() << "[IO] flush";}
};int main(int argc, char *argv[])
{QApplication app(argc, argv);auto& m = Model::GetInstance();std::shared_ptr<QtWidgetsApplication1> window = std::make_shared<QtWidgetsApplication1>();std::shared_ptr<UIObserver> UI = std::make_shared<UIObserver>();std::shared_ptr<IoObserver> OI = std::make_shared<IoObserver>();int64_t h1 = m.Register(UI);int64_t h2 = m.Register(OI);int64_t h3 = m.Register(window);window->show();return app.exec();
}
#pragma once#include <QtWidgets/QWidget>
#include "ui_QtWidgetsApplication1.h"
#include "Observer.h"class QtWidgetsApplication1 : public QWidget, public Observer
{Q_OBJECTpublic:QtWidgetsApplication1(QWidget *parent = nullptr);~QtWidgetsApplication1();void Execute() override;public slots:void onUpdate();void doUpdate(int v); // 在主线程执行private:Ui::QtWidgetsApplication1Class ui;int m_nCounter = 1;
};
#include "QtWidgetsApplication1.h"
#include <QPushButton>
#include <QThread>
#include <QDebug>QtWidgetsApplication1::QtWidgetsApplication1(QWidget *parent): QWidget(parent)
{ui.setupUi(this);connect(ui.btnUpdate, &QPushButton::clicked, this, &QtWidgetsApplication1::onUpdate);qDebug() << "Main thread ID: " << QThread::currentThreadId();
}QtWidgetsApplication1::~QtWidgetsApplication1()
{}void QtWidgetsApplication1::onUpdate()
{Model::GetInstance().Notify();
}void QtWidgetsApplication1::Execute()
{qDebug() << "Current thread ID: " << QThread::currentThreadId();if (thread() != QThread::currentThread()){QMetaObject::invokeMethod(this,"doUpdate",Qt::QueuedConnection,Q_ARG(int, m_nCounter++));}else{doUpdate(m_nCounter++);}
}void QtWidgetsApplication1::doUpdate(int v)
{if (thread() != QThread::currentThread()){qFatal("Execute is NOT in GUI thread!");}ui.lblValue->setText(QString::number(v));
}
#pragma once
#include <queue>
#include <mutex>
#include <thread>
#include <memory>
#include <vector>class Observer
{
public:virtual ~Observer() = default;virtual void Execute() = 0;
};using ObserverPtr = std::shared_ptr<Observer>;
using WeakObserverPtr = std::weak_ptr<Observer>;class Model
{
public:virtual ~Model();static Model& GetInstance(){static Model model;return model;}/*-----增*删*改*查-----*/int64_t Register(ObserverPtr sp); // 返回句柄,用于注销void Unregister(int64_t handle); // 删除void Notify(); // 异步通知(非阻塞)void NotifySync(); // 同步通知private:Model();struct Slot{int64_t handle;WeakObserverPtr wptr;};std::vector<Slot> m_slots;std::mutex m_mtx;int64_t m_nextHandle = 1;/*-----异步通知线程-----*/void Worker();std::thread m_worker;std::queue<int64_t> m_taskQueue;std::condition_variable m_cv;bool m_stop = false;
};
#include "Observer.h"
#include <iostream>int64_t Model::Register(ObserverPtr sp)
{std::lock_guard<std::mutex> lock(m_mtx);m_slots.push_back({ m_nextHandle, sp });return m_nextHandle++;
}void Model::Unregister(int64_t handle)
{std::lock_guard<std::mutex> lock(m_mtx);m_slots.erase(std::remove_if(m_slots.begin(), m_slots.end(),[=](const Slot& s) {return s.handle == handle; }),m_slots.end());
}// 同步通知(立即执行,会阻塞调用者)
void Model::NotifySync()
{std::lock_guard<std::mutex> lock(m_mtx);for (auto it = m_slots.begin(); it != m_slots.end();){if (auto sp = it->wptr.lock()){sp->Execute();++it;}else{it = m_slots.erase(it);}}
}// 异步通知(把任务抛给后台线程,调用者立即返回)
void Model::Notify()
{{std::lock_guard<std::mutex> lock(m_mtx);m_taskQueue.push(-1); // -1 代表“通知全部”}m_cv.notify_one();
}// 后台worker真正遍历并调用
void Model::Worker()
{while (true){std::unique_lock<std::mutex> lock(m_mtx);m_cv.wait(lock, [this] {return !m_taskQueue.empty() || m_stop; });if (m_stop){break;}auto todo = std::move(m_taskQueue);lock.unlock();while (!todo.empty()){int64_t cmd = todo.front();todo.pop();lock.lock();for (auto& s : m_slots){if (auto sp = s.wptr.lock()){sp->Execute();}}lock.unlock();}}
}Model::Model() :m_worker(&Model::Worker, this) {}Model::~Model()
{{std::lock_guard<std::mutex> lock(m_mtx);m_stop = true;m_cv.notify_all();}m_worker.join();
}