C++对象之间的调用,可以通过对象+成员函数的方式实现,一般情况下,被调用的对象定义为成员变量,然后就可以被调用者进行调用了,这称为单向调用。
单向调用指的是对象之间调用方向,函数调用只能从调用者对象调用被调用者对象。
但是有时对象之间的调用也是互相的,也就是双向调用,调用者和被调用者没有明确的界限,有时需要对象A调用对象B的函数,有时需要对象B调用对象A的功能。对象之间的互相调用的也可以实现,在QT中一般通过信号槽的方式实现,对象A的信号关联对象B的槽函数,就实现了A对B的“调用”;对象B信号关联对象A的槽函数,就实现了B对A的“调用”。由于A和B使用了不同的信号和槽函数,所以也就不会出现调用“冲突”的情况。
场景:
一个关于GIS的回放软件:工人拿着GPS和音视频设备(录音笔或者视屏记录仪)出去办公,回来之后复盘今天的工作情况,需要一面在地图上回放航迹,观看行走的位置,一面观看视频,还有同时听取录音情况。同时要求这三者之间的同步播放、暂停、快进、慢进等。也许你觉得这个功能比较简单,可以实现。在地图界面上添加一个工具条,上面有控制按钮,当点击不同的按钮时航迹实现相应的功能,同时给视屏播放器或者音频播放器发送消息实现就可以了。
这只是其中的一个功能。
由于采用多屏播放器,不同的屏幕播放不同的界面,一个屏幕播放航迹,一个屏幕播放视频,一个屏幕播放音频。当观看其中一个屏幕的时候,在需要的时候要暂停或者快进等。比如在观看视频的时候,发现异常,只能在视频播放的界面暂停,同时在航迹回放的时候也要同步的暂停,音频播放器也要暂停。用户可以去同时观看航迹的位置;在听音频的时候,听到不对的地方,在音频界面可以暂停音频,同时在航迹播放和视频播放也需要暂停。
以上需要也就是说,我只要操作任意一个界面上的按钮,就可以同时控制其他界面的功能,它们之间就是相互之间的调用。其中一个播放器功能并不是自己开发的而是使用的第三方的播放器,需要通过发送消息的方式实现控制。
当三者之间有相互调用关系的时候,这里面的调用逻辑就是比较复杂了。当其中一个发出消息控制其他的界面,其他界面接收到消息后,进行相应的处理,包括按钮的点击事件。但是当鼠标点击按钮时,也会出现按钮的点击事件。这里面就需要一些逻辑控制了。
为了解耦接收到的消息和鼠标本身的按钮机制,可以把所有的需要控制的对象,包括GPS航迹回放界面、音频界面、视频界面击中起来进行管理。
每种控制界面都需要有相同的功能(播放、暂停、快进、快退等),把这些相同的功能提取出来封装成一个基类:
//态势同步操作
class INTERFACEIMPL_EXPORT ISynchPlay {
public:
ISynchPlay();
~ISynchPlay();
//播放
virtual void synchPlay(void* runningTime, double rate = 1.0);
//运行时开始播放-态势正在运行
virtual void synchRunStartPlay(void* runningTime);
//暂停
virtual void synchPause(void* runningTime);
//跳到某时间
virtual void synchJumpTo(void* runningTime);
//下一秒
virtual void synchForwardFrame(void* runningTime);
//上一秒
virtual void synchBackwardFrame(void* runningTime);
//加速
virtual void synchAccelerateRate(double rate);
//减速
virtual void synchDecelerateRate(double rate);
};
ISynchPlay::ISynchPlay() {
}
ISynchPlay::~ISynchPlay() {
}
void ISynchPlay::synchPlay(void* runningTime, double rate) {
}
void ISynchPlay::synchRunStartPlay(void* runningTime) {
}
void ISynchPlay::synchPause(void* runningTime) {
}
void ISynchPlay::synchJumpTo(void* runningTime) {
}
void ISynchPlay::synchForwardFrame(void* runningTime) {
}
void ISynchPlay::synchBackwardFrame(void* runningTime) {
}
void ISynchPlay::synchAccelerateRate(double rate) {
}
void ISynchPlay::synchDecelerateRate(double rate) {
}
然后定义一个共有对象基类,用来表示控制界面:
class INTERFACEIMPL_EXPORT IMediationObj:public ISynchPlay {
public:
IMediationObj();
~IMediationObj();
protected:
};
然后就是三个功能模块分别继承这个对象基类,并且实现相应的功能。
为了便于管理这些对象需要,把这些对象保存起来统一进行管理:
class INTERFACEIMPL_EXPORT MediaObjManager {
private:
MediaObjManager();
static MediaObjManager*_instance;
public:
static MediaObjManager*getInstance();
void saveMediaObj(MediaObjType t, IMediationObj* obj);
IMediationObj* loadMediaObj(MediaObjType t);
std::map<MediaObjType, IMediationObj*>&getMediaObj() {
return _mediaObj;
}
private:
std::map<MediaObjType, IMediationObj*> _mediaObj;
};
MediaObjManager::MediaObjManager() {
}
MediaObjManager* MediaObjManager::_instance = new MediaObjManager;
MediaObjManager* MediaObjManager::getInstance() {
return _instance;
}
void MediaObjManager::saveMediaObj(MediaObjType t, IMediationObj* obj) {
_mediaObj[t] = obj;
}
IMediationObj* MediaObjManager::loadMediaObj(MediaObjType t) {
return _mediaObj[t];
}
不同的界面定义不同标志已示区别:
enum MediaObjType {
MEDIAOBJ_UI,//回放界面
MEDIAOBJ_MAP,//地图GPS
MEDIAOBJ_MP4,//MP4播放
MEDIAOBJ_AUDIO,//音频播放
};
定义三者同步播放的管理器:
class VIDEOREPLAY_EXPORT PlayMediator {
private:
PlayMediator();
static PlayMediator* _instance;
public:
~PlayMediator();
static PlayMediator* getInstance();
//播放
void synchPlay(MediaObjType objType, void* runningTime, double rate = 1.0);
//开始同步播放
void synchRunStartPlay(MediaObjType objType, void* runningTime);
//暂停
void synchPause(MediaObjType objType, void* runningTime);
//跳转
void synchJumpTo(MediaObjType objType, void* runningTime);
//向前
void synchForwardFrame(MediaObjType objType, void* runningTime);
//向后
void synchBackwardFrame(MediaObjType objType, void* runningTime);
//加速
void synchAccelerateRate(MediaObjType objType, double rate);
//减速
void synchDecelerateRate(MediaObjType objType, double rate);
};
PlayMediator* PlayMediator::_instance = new PlayMediator;
PlayMediator::PlayMediator() {
}
PlayMediator::~PlayMediator() {
}
PlayMediator* PlayMediator::getInstance() {
return _instance;
}
void PlayMediator::synchPlay(MediaObjType objType, void* runningTime, double rate) {
std::map<MediaObjType, IMediationObj*>&mediaObj = MeObjMgr()->getMediaObj();
int num = mediaObj.size();
for (auto m: mediaObj){
if (m.first != objType) {
m.second->synchPlay(runningTime);
}
}
}
void PlayMediator::synchRunStartPlay(MediaObjType objType, void* runningTime) {
std::map<MediaObjType, IMediationObj*>&mediaObj = MeObjMgr()->getMediaObj();
int num = mediaObj.size();
for (auto m : mediaObj) {
if (m.first != objType) {
m.second->synchRunStartPlay(runningTime);
}
}
}
void PlayMediator::synchPause(MediaObjType objType, void* runningTime) {
std::map<MediaObjType, IMediationObj*>&mediaObj = MeObjMgr()->getMediaObj();
int num = mediaObj.size();
for (auto m : mediaObj) {
if (m.first != objType) {
m.second->synchPause(runningTime);
}
}
}
void PlayMediator::synchJumpTo(MediaObjType objType, void* runningTime) {
std::map<MediaObjType, IMediationObj*>&mediaObj = MeObjMgr()->getMediaObj();
int num = mediaObj.size();
for (auto m : mediaObj) {
if (m.first != objType) {
m.second->synchJumpTo(runningTime);
}
}
}
void PlayMediator::synchForwardFrame(MediaObjType objType, void* runningTime) {
std::map<MediaObjType, IMediationObj*>&mediaObj = MeObjMgr()->getMediaObj();
int num = mediaObj.size();
for (auto m : mediaObj) {
if (m.first != objType) {
m.second->synchForwardFrame(runningTime);
}
}
}
void PlayMediator::synchBackwardFrame(MediaObjType objType, void* runningTime) {
std::map<MediaObjType, IMediationObj*>&mediaObj = MeObjMgr()->getMediaObj();
int num = mediaObj.size();
for (auto m : mediaObj) {
if (m.first != objType) {
m.second->synchBackwardFrame(runningTime);
}
}
}
void PlayMediator::synchAccelerateRate(MediaObjType objType, double rate) {
std::map<MediaObjType, IMediationObj*>&mediaObj = MeObjMgr()->getMediaObj();
int num = mediaObj.size();
for (auto m : mediaObj) {
if (m.first != objType) {
m.second->synchAccelerateRate(rate);
}
}
}
void PlayMediator::synchDecelerateRate(MediaObjType objType, double rate) {
std::map<MediaObjType, IMediationObj*>&mediaObj = MeObjMgr()->getMediaObj();
int num = mediaObj.size();
for (auto m : mediaObj) {
if (m.first != objType) {
m.second->synchDecelerateRate(rate);
}
}
}
以上就可以实现了三者之间只要任意控制其中的一个界面,其他的界面也就可以同步的实现了!
这里面有中介者?
有的,对象管理器就是一个中介MediaObjManager,当其中的一个界面需要同步娶她的界面的时候,不必直接控制其他的界面,而是使用这个中介者就可以进行控制了,减少了类之间的耦合。
aaa