您的位置:首页 > 其它

模块间互相调用的一种方法

2009-06-22 14:54 441 查看
模块间互相调用的一种方法
在程序设计中,需要把程序根据功能划分多个模块,多个模块间免不了互相调用一些服务函数,这样会使模块间剪不断,理还乱!
利用服务中心的思想,可以使各个模块间的关系比较简单。模块间的调用通过中心服务器交换,彼此没有联系,这样模块间可以到达低耦合,高内聚。

实现方法:

中心服务器:

class BASEFRAME_CLASS CIVMDlgSrvMgr
{
typedef map<string,CIVMBaseSrv*> SRVMAP;
typedef map<string,CIVMBaseSrv*>::iterator SRVMAPPtr;

typedef map<CIVMBaseSrv*,CIVMBaseSrv*> DLGMAP;
typedef map<CIVMBaseSrv*,CIVMBaseSrv*>::iterator DLGMAPPtr;

public:
CIVMDlgSrvMgr();
virtual ~CIVMDlgSrvMgr();

public:
static CIVMDlgSrvMgr* Instance();
// 注册一个服务
bool RegService( string strSrvName, CIVMBaseSrv* pProvider );
// 注销一个服务
void UnRegService( string strSrvName );
// 注销一个服务提供者
void UnRegProvider( CIVMBaseSrv* pProvider );
// 请求一个服务
bool QueryService( IN CIVMMsg& msg, OUT CIVMMsg& result );
// 注册一个窗口
void RegDlg( CIVMBaseSrv* pDlg );
// 注销一个窗口
void UnRegDlg( CIVMBaseSrv* pDlg );
//
void CloseNoneVideoWnd();
//
void DiableAllWnd();
//
void EnableAllWnd();
//
CIVMBaseSrv* GetRegDlg( string strDlgClassName );

protected:
SRVMAP m_srvMap;
DLGMAP m_dlgMap;

};
在程序中,定一个中心服务器单体:
CIVMDlgSrvMgr* g_pSrvMgr = NULL;

CIVMDlgSrvMgr* g_pSrvMgr = NULL;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CIVMDlgSrvMgr::CIVMDlgSrvMgr()
{

}

CIVMDlgSrvMgr::~CIVMDlgSrvMgr()
{

}

CIVMDlgSrvMgr* CIVMDlgSrvMgr::Instance()
{
if ( g_pSrvMgr == NULL )
{
g_pSrvMgr = new CIVMDlgSrvMgr();
ASSERT( g_pSrvMgr );
}

return g_pSrvMgr;
}

// 注册一个服务
bool CIVMDlgSrvMgr::RegService( string strSrvName, CIVMBaseSrv* pProvider )
{
m_srvMap[strSrvName] = pProvider;
return true;
}

// 注销一个服务
void CIVMDlgSrvMgr::UnRegService( string strSrvName )
{
m_srvMap.erase(strSrvName);
}

// 注销一个服务提供者
void CIVMDlgSrvMgr::UnRegProvider( CIVMBaseSrv* pProvider )
{
SRVMAPPtr itSrv = m_srvMap.begin();
for ( ; itSrv != m_srvMap.end(); itSrv++ )
{
if ( itSrv->second == pProvider )
{
itSrv = m_srvMap.erase( itSrv );
}
}
}

// 请求一个服务
//用户需要调用另外一个模块的服务函数时,调用该函数。前提是:另外一个模块提供了这个服务函数,并向中心服务器注册了该函数,如何注册,下面会做介绍。
bool CIVMDlgSrvMgr::QueryService(IN CIVMMsg& msg, OUT CIVMMsg& result)
{
string strQuerySrvName = msg.GetMsgName();
CIVMBaseSrv* pSrvProvider = m_srvMap[strQuerySrvName];
if ( pSrvProvider == NULL )
{
return false;
}

return pSrvProvider->OnQueryMsg( msg, result );
}

// 注册一个窗口
void CIVMDlgSrvMgr::RegDlg( CIVMBaseSrv* pDlg )
{
m_dlgMap[pDlg] = pDlg;
}

// 注销一个窗口
void CIVMDlgSrvMgr::UnRegDlg( CIVMBaseSrv* pDlg )
{
DLGMAPPtr itDlg = m_dlgMap.begin();
for ( ; itDlg != m_dlgMap.end(); itDlg++ )
{
if ( itDlg->second == pDlg )
{
m_dlgMap.erase( itDlg );

break;
}
}
}

CIVMBaseSrv* CIVMDlgSrvMgr::GetRegDlg( string strDlgClassName )
{
CIVMBaseDlg* pDlg = NULL;
DLGMAPPtr itDlg = m_dlgMap.begin();
for ( ; itDlg != m_dlgMap.end(); itDlg++ )
{
pDlg = (CIVMBaseDlg*)(itDlg->second);
if ( pDlg && pDlg->m_strDlgName == strDlgClassName )
{
return pDlg;
}
}

return NULL;
}

void CIVMDlgSrvMgr::DiableAllWnd()
{
CIVMBaseDlg* pWnd= NULL;
DLGMAPPtr itDlg = m_dlgMap.begin();
for ( ; itDlg != m_dlgMap.end(); itDlg++ )
{
pWnd = (CIVMBaseDlg*)itDlg->second;
if ( pWnd && IsWindow(pWnd->m_hWnd) )
{
pWnd->EnableWindow(FALSE);
}
}
}

void CIVMDlgSrvMgr::EnableAllWnd()
{
CIVMBaseDlg* pWnd= NULL;
DLGMAPPtr itDlg = m_dlgMap.begin();
for ( ; itDlg != m_dlgMap.end(); itDlg++ )
{
pWnd = (CIVMBaseDlg*)itDlg->second;
if ( pWnd && IsWindow(pWnd->m_hWnd) )
{
pWnd->EnableWindow(TRUE);
}
}
}

//
void CIVMDlgSrvMgr::CloseNoneVideoWnd()
{
CIVMBaseDlg* pWnd= NULL;
DLGMAPPtr itDlg = m_dlgMap.begin();
for ( ; itDlg != m_dlgMap.end(); itDlg++ )
{
pWnd = (CIVMBaseDlg*)itDlg->second;
if ( pWnd && IsWindow(pWnd->m_hWnd) && pWnd->m_strDlgName != "CIVMMonitorDlg")
{
pWnd->SendMessage(WM_CLOSE);
}
}
}

模块基类:

模块需要继承一个统一接口,向中心服务器注册自己提供的服务函数,和调用中心服务器提供的接口来调用其他模块的函数。
基类定义:
//////////////////////////////////////////////////////////////////////////
// 服务类接口
class BASEFRAME_CLASS CIVMBaseSrv
{
public:
CIVMBaseSrv(){};
~CIVMBaseSrv(){};

// 服务响应函数
virtual bool OnQueryMsg( CIVMMsg& msg, CIVMMsg& result );

// 获取提供的服务名列表
virtual bool GetSrvList( list<string>& srvList ){ return false; }

protected:
// 注册自己的服务
virtual bool RegistThisSrv()
{
bool bRet = true;
list<string> srvList;
if ( GetSrvList(srvList) )
{
list<string>::iterator itSrv = srvList.begin();
for ( ; itSrv != srvList.end(); itSrv++ )
{
bRet &= CIVMDlgSrvMgr::Instance()->RegService( *itSrv, this );
}
}

return bRet;
}

// 注销自己的服务
virtual void UnRegistThisSrv()
{
CIVMDlgSrvMgr::Instance()->UnRegProvider( this );
}
};

模块使用中心服务器互相调用的方法:

1. 模块要继承基类CIVMBaseSrv
2. 在启动模块时,调用
// 注册窗口提供的服务
RegistThisSrv();
并实现:
// 获取提供的服务名列表
bool CIVMEQMainDlg::GetSrvList( list<string>& srvList )
{
if ( m_bHasRecSrv == false )
{
return false;
}

srvList.push_back( SRV_EQ_STATUS );
srvList.push_back( SRV_EQ_FRESH );
srvList.push_back( SRV_EQ_CLEAR );
#ifdef _DIANLI_SMS_
srvList.push_back( SRV_SMTK_CONTROL_CYCLE );
#endif

return true;
}
来注入自己提供的服务名称。
3. 实现自己提供的服务函数
4. // 服务响应函数
bool CIVMEQMainDlg::OnQueryMsg( CIVMMsg& msg, CIVMMsg& result )
{
IVMFUNCTRACE("CIVMEQMainDlg::OnQueryMsg");

int nRecID = 0;
string strMsgName = msg.GetMsgName();
CIVMMsgBody* pBody = msg.GetBody();
string strTmp = msg.ToString();

if ( strMsgName == SRV_EQ_STATUS )
{
char* pszPUID = pBody->GetTag( "PUID", true );
char* pszChnNo = pBody->GetTag( "ChnNo", true );
CIVMEQTree::ENDoOnVChn nArm =
pBody->GetTagInt( "Arm", true ) == 1 ? CIVMEQTree::DOV_ARMSTART : CIVMEQTree::DOV_ARMSTOP;

if ( pszPUID && pszChnNo )
{
CIVMDataItemVChn* pChn = m_eqtree.m_pEQData->GetChn( pszPUID, pszChnNo );
if (pChn != NULL)
{
if ( nArm == CIVMEQTree::DOV_ARMSTART )
{
pChn->Arm( 0 );
}
else
{
pChn->DisArm();
}
}
}
}
else if ( strMsgName == SRV_EQ_FRESH )
{
(void)m_eqtree.FreshTreeData();
}
else if ( strMsgName == SRV_EQ_CLEAR )
{
StopTimer();

StopAllVideo();

LOCK_DATA(m_eqtree.m_pEQData);
StopAllVideo();
m_eqtree.m_pEQData->Clear();
UNLOCK_DATA(m_eqtree.m_pEQData);

(void)m_eqtree.FreshTreeData();

StartTimer();
}
#ifdef _DIANLI_SMS_
else if ( strMsgName == SRV_SMTK_CONTROL_CYCLE )
{
CIVMMsgNode* pNode = msg.GetSingleNode("ControlSMTK");
ASSERT( pNode );

if ( pNode )
{
char* pszAction = pNode->GetTag(TAG_ACTION);
if ( NULL == pszAction )
return false;
int nAction = atoi(pszAction);
string strEQID = "";
CIVMDataItemEQ* pEQ = NULL;
strEQID = pNode->GetTag("PUID");
if (!strEQID.empty())
{
pEQ = m_eqtree.m_pEQData->GetDataItem(strEQID);
if ( NULL == pEQ )
return false;
}
//判断action的值来决定是启动SMTK还是关闭SMTK
if ( nAction == 1 )//唤醒电源系统
{
//m_eqtree.OpenMainCtrlMoudle(pEQ);
m_eqtree.SMSOperate(pEQ, 2);
}
else if ( nAction == 0) //休眠电源系统
{
//m_eqtree.CloseMainCtrlMoudle(pEQ);
//
m_eqtree.SMSOperate(pEQ, 3);
}
}
}
#endif
else
{
ASSERT( 0 );
}

return nRecID > 0 ? true : false;
}

这样其他模块就可以根据服务名字来调用该模块的服务函数。注意:
1. 服务函数不能阻塞,否则会引起调用者的阻塞。
2. CIVMMsg只是一个XML结构体,用户可以自己实现。
3. 调用服务函数的结果放在, CIVMMsg& result中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: