类或对象之间的建立联系的方法很多:如(1)用组合的方式,一个类做为另一个类的成员变量。(2)两个类都作为基类的成员,通过基类调用另一个类。(3)想办法捞到另一个类的句柄,给另一个类发消息。(4)还有,受人诟病的 全局变量也是一种方式呀。我们今天要 讨论的是通过一个 中间类 来实现两个类之间的通信。
事出有因,项目中有一个比较简单的功能,就是下载的同时要保证界面要同时刷新。如果是mfc,发个消息 SendMessage(lListView, LVM_SETITEM, iCol, (LPARAM)(const LPLVITEM)&Myliveitem);让mfc自己去处理吧。但我用的是金山的框架,所以具体的刷新工作我还得做。我要使得负责下载的CDownLoadCmd和负责界面刷新的CAutoProductUIHandler之间通信。
我还需要两个类,一个含有注册方法的CCommandEventMediator,另一个是含有需实现接口的CUpdateEvent。
CommandEventMediator.h
#include "UpdateEvent.h"
#pragma once
class CCommandEventMediator : private set<CUpdateEvent*>
{
public:
enum EVENT_CONSTANTS
{
DOWNLOADINITCOMPLETE = 1,
DOWNLOADPROCESS = 2,
NOFRESH = 3, // 提示 没有更新
UPDATECOMPLETE = 4,
UPDATEPROCESS = 5,
DOWNLOADCREATE = 6,
DOWNLOADINITSTART = 7,
UPDATEEND = 8,
NETCONNECTFAILURE=9,
SRVNOPUBLISHED=10,
ALLPRODUCTUPDATERESULT=11,
};
void Register(CUpdateEvent *pUpdateEvent);
void Unregister(CUpdateEvent *pUpdateEvent);
void InvokeEvent(EVENT_CONSTANTS enumEvent, CDownLoadCmd *pDownLoadCmd = NULL,CAutoCommand *pAutoCommand = NULL );
};
typedef SingletonHolder<CCommandEventMediator, CreateUsingNew, PhoenixSingleton> TheCommandEventMediator;
1.注册,也就是把需要响应的类如:CAutoProductUIHandler的指针插入到集合set中。
void CCommandEventMediator::Register(CUpdateEvent *pUpdateEvent)
{
insert( pUpdateEvent );
}
例如:CAutoProductUIHandler需要响应CDownLoadCmd下载过程中界面的刷新,这时我就得把CAutoProductUIHandler的实例做下注册。
CAutoProductUIHandler::CAutoProductUIHandler(CUpdateListDlg *pDialog)
{
TheCommandEventMediator::Instance().Register(this);
...
}
2.调用事件。
void CCommandEventMediator::InvokeEvent(EVENT_CONSTANTS enumEvent, CDownLoadCmd *pDownLoadCmd,CAutoCommand *pAutoCommand )
{
switch (enumEvent)
{
...
case DOWNLOADPROCESS:
{
for(iterator iter = begin(); iter != end(); iter++)
{
CUpdateEvent* pTemp = (*iter);
if( pTemp ) pTemp->OnDownloadProcess( pDownLoadCmd );
}
break;
}
...
}
}
这个InvokeEvent尤为重要,如A要给B通信,A就可以调用InvokeEvent,并用一个宏做参数,而B负责实现对应宏下面的接口。
如:我在CDownLoadCmd中调用InvokeEvent。
void CDownLoadCmd::_RefeshPos()
{
...
TheCommandEventMediator::Instance().InvokeEvent(CCommandEventMediator::DOWNLOADPROCESS,this);
...
}
在CAutoProductUIHandler负责实现CUpdateEvent提供的相关接口。
class CAutoProductUIHandler : public CUpdateEvent
void CAutoProductUIHandler::OnDownloadProcess( CDownLoadCmd *pDownLoadCmd )
{
if (m_pMainDlg->IsWindow() && m_pMainDlg->IsWindowVisible())
RefreshItem(pDownLoadCmd->GetID());
}
3.扩展
其实,设计模式中的Observer与之非常相似。正如我们或许曾遇到的面试题一样:猫叫,老鼠跑,主人醒。
可以设计成:老鼠,主人都是继承自Observer。而猫这个类维护这个列表
list<Observer*>::iterator it;
it = _obvs->begin();
for (;it != _obvs->end();it++)
{
//关于模版和iterator的用法
(*it)->Update(this);
}
老鼠和主人肯定对Update都有各自的实现。