前言
Qt项目开发,信号槽是必然使用到的。简单项目直接绑定对象信号传递没问题,但项目稍具规模对象父子关系变多,那么信号的传递必然要跨越多层,需要多层连续转发,这种多层传递是可以使用,原理上也没有任何问题,但是增大了代码复杂度也容易遗漏造成逻辑错误。这时可以考虑引入全局信号转发类优化代码,优雅的解决此问题。
原理
思路其实很简单,对于三层关系A-B-C,A到C的信号通知可以通过B来转发。但实际开发项目中的层级关系往往更深,A-B-C-D、A-B-C-D-E大于三层这种占比更大。增加一个全局信号单例类便可以只进行一次转发即可,如A-转发类-D,A-转发类-E。因为一般只是转发没什么太大性能消耗,所以一个全局转发类设置为单例即可,当然设置多个全局转发类也可以但没必要。
代码
代码摘抄自个人FFmpeg播放器核心剖析AVPlayer项目中。对于单例模式网上资料很多不再赘述,个人喜欢饿汉模式,主要原因有两点:1.不需要考虑线程安全性问题 2. 单例既然设计一般程序逻辑中或早或晚都是会用到的,不如直接创建准备好,内存优先级小于程序稳定性。选择因人而异,下面贴出代码。
头文件
#ifndef GLOBAL_H
#define GLOBAL_H
#include <QObject>
//全局信号转发单例类
class GlobalObj : public QObject
{
Q_OBJECT
public:
//获取单实例
static GlobalObj* getInstance();
//释放单实例
static void deleteInstance();
signals:
//时长
void sigMediaDuration(int duration);
//播放位置
void sigSendPlayPos(qint64 pos);
//播放结束
void sigMediaFinish();
private:
//构造、析构、拷贝构造、赋值构造私有
GlobalObj(){}
~GlobalObj(){}
GlobalObj(const GlobalObj &){}
const GlobalObj &operator=(const GlobalObj &){}
private:
//单实例对象指针
static GlobalObj *obj;
};
//全局参数类
class GlobalData
{
public:
static QString version;
};
实现文件
#include "global.h"
//全局信号转发单例类
GlobalObj* GlobalObj::obj = new GlobalObj();
GlobalObj *GlobalObj::getInstance()
{
return obj;
}
void GlobalObj::deleteInstance()
{
if(obj)
{
delete obj;
obj = nullptr;
}
}
//全局参数类
QString GlobalData::version = "1.0";
更新版
更新新的单例实现方式,基于C++11
class GlobalObj : public QObject
{
Q_OBJECT
public:
//获取单实例 线程安全
//静态局部变量只在第一次被调用时初始化,位于静态存储区,生命周期从初始化起至程序结束止
static GlobalObj *getInstance()
{
static GlobalObj obj;
return &obj;
}
signals:
//时长
void sigMediaDuration(int duration);
//播放位置
void sigSendPlayPos(qint64 pos);
//播放结束
void sigMediaFinish();
private:
//构造、析构、拷贝构造、赋值构造私有
GlobalObj(){}
~GlobalObj(){}
GlobalObj(const GlobalObj &) = delete;
const GlobalObj &operator=(const GlobalObj &) = delete;
};
调用示例
//底层信号发至转发类
GlobalObj *obj = GlobalObj::getInstance();
connect(this, &AVDemuxer::sigMediaDuration, obj, &GlobalObj::sigMediaDuration);
connect(this, &AVDemuxer::sigMediaFinish, obj, &GlobalObj::sigMediaFinish);
//to do other..
//转发类信号发至界面
GlobalObj *obj = GlobalObj::getInstance();
connect(obj, &GlobalObj::sigMediaDuration, this, &Widget::slotMediaDuration);
connect(obj, &GlobalObj::sigSendPlayPos, this, &Widget::slotSendPlayPos);
connect(obj, &GlobalObj::sigMediaFinish, this, &Widget::slotMediaFinish);
//to do other..