Qt事件耦合器实现(类似C#的Prism中的事件耦合器)

发布于:2022-12-22 ⋅ 阅读:(520) ⋅ 点赞:(0)

        该耦合器提供了一种事件机制,可以实现应用程序中松散耦合组件之间的通信。这种机制基于事件聚合器服务,允许发布者和订阅者通过事件进行通信,并且彼此之间仍然没有直接引用。简单来说就是提供了一个多播发布/订阅功能。

 看上图了解事件耦合器。

Qt中自带的信号/槽也是一种解耦机制,但是当项目做大后要写好多connect来链接关系,有了事件耦合器后就不需要connect了。

1、创建事件

testeventargs.h:
#ifndef TESTEVENTARGS_H
#define TESTEVENTARGS_H

#include "Event/baseeventargs.h"
class TestEventArgs : public BaseEventArgs
{
public:
    explicit TestEventArgs();

    int getId() const;
    void setId(int value);

    QString getName() const;
    void setName(const QString &value);

    QString toString();

private:
    int id;
    QString name;

};

#endif // TESTEVENTARGS_H


testeventargs.cpp
#include "testeventargs.h"


TestEventArgs::TestEventArgs() : BaseEventArgs()
{

}

int TestEventArgs::getId() const
{
    return id;
}

void TestEventArgs::setId(int value)
{
    id = value;
}

QString TestEventArgs::getName() const
{
    return name;
}

void TestEventArgs::setName(const QString &value)
{
    name = value;
}

QString TestEventArgs::toString()
{
    return QString("id=%1,name=%2").arg(id).arg(name);
}

2、订阅事件

//订阅
void Widget::on_btnSub_clicked()
{
    Function<void(TestEventArgs)> func(this, &Widget::dealEvent);
    EventAggregator::GetEvent<TestEvent>()->Subscribe(func);
}

//处理事件
void Widget::dealEvent(TestEventArgs args)
{
    ui->label->setText(args.toString());
}

3、发布事件

//发布
void Widget::on_btnPub_clicked()
{
    TestEventArgs args;
    args.setId(1);
    args.setName("Test Event");
    EventAggregator::GetEvent<TestEvent>()->Puslish(args);
}

这样,一个发布/订阅的事件就完成了,也可以在任何时候取消事件注册,只需要调用Unsubscribe方法即可

EventAggregator::GetEvent<TestEvent>()->Unsubscribe(func);

源码:

baseeventargs.h

#ifndef DKBASEEVENTARGS_H
#define DKBASEEVENTARGS_H
#include <QFuture>

/**
 * @brief 事件参数基类
 */
class BaseEventArgs
{
public:
    ~BaseEventArgs()
    {

    }
    bool isSync() const
    {
        return m_sync;
    }
    void setSync(bool sync)
    {
        m_sync = sync;
    }

private:
    /**
     * @brief 是否同步执行事件 true-同步 false-异步
     * 注:发布和订阅同一线程中既可以选择同步也可以选择异步,否则只能选择异步;异步调用中使用QMetaObject::invokeMethod
     */
    bool m_sync = true;
};

#endif // DKBASEEVENTARGS_H
eventaggregator.h
#ifndef DKEVENTAGGREGATOR_H
#define DKEVENTAGGREGATOR_H

#include <QObject>
#include <QMap>
#include <QString>
#include <QMutex>

/**
 * @brief 事件耦合器
 */
class EventAggregator : public QObject
{
    Q_OBJECT
    /**
     * @brief 事件对象map(key-事件类型名,value-事件对象)
     */
    static QMap<QString,QObject*> m_map;
    /**
     * @brief 互斥锁
     */
    static QMutex *m_pMutex;
public:
    explicit EventAggregator(QObject *parent = nullptr);

    /**
     * @brief 获取模板类型的事件对象
     * @return 指定类型事件对象
     */
    template<typename EventType>
    static EventType* GetEvent()
    {
        EventType *pEvent;
        QString className = typeid (EventType).name();
        if(m_map.contains(className))
        {
            pEvent = static_cast<EventType*>(m_map[className]);
        }
        else
        {
            pEvent = new EventType;
            m_pMutex->lock();
            m_map.insert(className,pEvent);
            m_pMutex->unlock();
        }
        return pEvent;
    }

};

#endif // DKEVENTAGGREGATOR_H

 eventaggregator.cpp

#include "eventaggregator.h"

EventAggregator::EventAggregator(QObject *parent) : QObject(parent)
{

}

QMap<QString,QObject*> EventAggregator::m_map = QMap<QString,QObject*>();

QMutex* EventAggregator::m_pMutex = new QMutex();

eventbase.h

#ifndef DKEVENTBASE_H
#define DKEVENTBASE_H

#include <QObject>

/**
 * @brief 事件基类
 */
class EventBase : public QObject
{
    Q_OBJECT
public:
    explicit EventBase(QObject *parent = nullptr);

};

#endif // DKEVENTBASE_H

eventbase.cpp

#include "eventbase.h"

EventBase::EventBase(QObject *parent) : QObject(parent)
{

}

function.h

#ifndef DKFUNCTION_H
#define DKFUNCTION_H

#include <QUuid>
#include <functional>

/**
 * @brief函数封装类
 */
template<class T>
class Function
{
private:
    QUuid m_uuid;
    bool m_isEnable = true;
public:
    std::function<T> call;
public:
    Function(): m_uuid(QUuid::createUuid())
    {

    }
    Function(std::function<T> func): Function()
    {
        this->call = func;
    }
    template<typename t1, typename t2>
    Function(t1 pOwner, t2 pFunc): Function()
    {
        call = std::bind(pFunc, pOwner, std::placeholders::_1);
    }

    bool operator==(const Function& func)
    {
        return this->m_uuid == func.m_uuid;
    }

    Function& operator=(const std::function<T>& func)
    {
        call = func;
        return *this;
    }


    /**
     * @brief 设置成员变量函数
     * @param pOwner 成员函数所属对象指针
     * @param pFunc 成员函数指针
     */
    template<typename t1, typename t2>
    void setMemberFunction(t1 pOwner, t2 pFunc)
    {
        call = std::bind(pFunc, pOwner, std::placeholders::_1);
    }

    /**
     * @brief 设置普通函数、匿名函数和std::function类型仿函数
     * @param pFunc 函数指针
     */
    template<typename t1>
    void setFunction(t1 pFunc)
    {
        call = pFunc;
    }
    bool isEnable() const
    {
        return m_isEnable;
    }
    void setIsEnable(bool isEnable)
    {
        m_isEnable = isEnable;
    }
};

#endif // DKFUNCTION_H

pubsubevent.h

#ifndef DKPUBSUBEVENT_H
#define DKPUBSUBEVENT_H

#include <QList>
#include <functional>
#include <QtConcurrent>
#include "Event/eventbase.h"
#include "Event/function.h"
#include "Event/baseeventargs.h"

/**
 * @brief 订阅发布事件
 */
template <class TPayload>
class PubSubEvent: public EventBase
{
    typedef Function<void(TPayload)> FuncType;
private:
    QList<FuncType> m_list;
    QMutex m_mutex;
public:
    PubSubEvent(QObject* parent = nullptr): EventBase(parent)
    {

    }

    PubSubEvent& operator+=(FuncType func)
    {
        m_mutex.lock();
        if(!m_list.contains(func))
        {
            m_list.append(func);
        }
        m_mutex.unlock();
        return *this;
    }

    PubSubEvent& operator-=(FuncType func)
    {
        m_mutex.lock();
        m_list.removeOne(func);
        m_mutex.unlock();
        return *this;
    }

    void operator()(TPayload payload, bool isSync = true)
    {
        BaseEventArgs& event = static_cast<BaseEventArgs&>(payload);
        event.setSync(isSync);
        for(auto dkFunc : m_list)
        {
            if(isSync)
            {
                dkFunc.call(payload);
            }
            else
            {
                QtConcurrent::run(dkFunc.call, payload);
            }
        }
    }

    /**
     * @brief 发布事件
     * @param payload 事件载体,即事件参数
     * @param isSync 是否同步执行
     */
    void Puslish(TPayload payload, bool isSync = true)
    {
        BaseEventArgs& eventArgs = static_cast<BaseEventArgs&>(payload);
        eventArgs.setSync(isSync);
        for(auto dkFunc : m_list)
        {
            if(dkFunc.isEnable())
            {
                if(isSync)
                {
                    dkFunc.call(payload);
                }
                else
                {
                    QtConcurrent::run(dkFunc.call, payload);
                }
            }
        }
    }


    /**
     * @brief 订阅事件
     * @param func 处理事件的函数
     */
    void Subscribe(FuncType& func)
    {
        m_mutex.lock();
        if(!m_list.contains(func))
        {
            m_list.append(func);
        }
        m_mutex.unlock();
    }

    /**
     * @brief 取消订阅事件
     * @param func 订阅事件的函数
     */
    void Unsubscribe(FuncType& func)
    {
        m_mutex.lock();
        m_list.removeOne(func);
        m_mutex.unlock();
    }
};

#endif // DKPUBSUBEVENT_H

源码下载地址:

Qt事件耦合器示例程序-C++文档类资源-CSDN下载

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到