修改了 INetwordable 接口, 將網(wǎng)絡(luò)程序中的“網(wǎng)絡(luò)通信”抽離出來,方便寫單元測試
#include?<windows.h>
#include?<iostream>
using?namespace?std;

//??網(wǎng)絡(luò)通信協(xié)議?

/**///////////////////////////////////////////////////////////////////////////////?//?
struct?cmd


{
????int?nCmd;
};

#pragma?pack(1)
struct??tagClientLogin


{
????cmd??header;
????char??username[?20?];
????char??userpwd[?20?];
}?;

struct??tagRepClientLogin


{
????cmd??header;
????bool??bLoginSuccess;
};
#pragma?pack(1)

#define??NETWORK_CMD_LOGIN?1?
#define??NETWORK_CMD_REP_LOGIN?2?

/**/////////////////////////////////////////////////////////////////////////////////?

//??接口定義?

/**/////////////////////////////////////////////////////////////////////////////////?
class??ClientObserver


{
public?:

????ClientObserver()???
{}?

????~?ClientObserver()?
{}?
????
????virtual?void?onRepLogin(?bool??bLoginSuccess)??=???0?;
}?;


/**//*
class?INetWorkable
{
public?:
????INetWorkable()??{}?
????~INetWorkable()?{}?
????
????//??pvoid?:?欲發(fā)送的緩沖區(qū);?nSize?:?緩沖區(qū)的大小?
????virtual?bool??send(?const???void?*??pvoid,??int??nSize)?=?0?;
????
????//??由網(wǎng)絡(luò)層調(diào)用,pvoid:?接收到的數(shù)據(jù)的緩沖區(qū),?nSize?:?緩沖區(qū)的大小;??返回已經(jīng)處理的數(shù)據(jù)長度?
????virtual?int?onreceive(?const???void?*??pvoid,??int??nSize)?=?0?;
};
*/

//?將原先的?INetWorkable?接口拆分成兩個類
class?INetWorkSendable


{
public?:

????INetWorkSendable()??
{}?

????~INetWorkSendable()?
{}?
????
????//??pvoid?:?欲發(fā)送的緩沖區(qū);?nSize?:?緩沖區(qū)的大小?
????virtual?bool??send(?const???void?*??pvoid,??int??nSize)?=?0?;
};

class?INetWorkRecvable


{
public?:

????INetWorkRecvable()??
{}?

????~INetWorkRecvable()?
{}?
????
????//??由網(wǎng)絡(luò)層調(diào)用,pvoid:?接收到的數(shù)據(jù)的緩沖區(qū),?nSize?:?緩沖區(qū)的大小;??返回已經(jīng)處理的數(shù)據(jù)長度?
????virtual?int?onreceive(?const???void?*??pvoid,??int??nSize)?=?0?;
};

class?ILogable


{
public?:

????ILogable()???
{}?

????~?ILogable()???
{}?
????
????virtual?void?log(const?char*?plog)?=?0;
};

/**/////////////////////////////////////////////////////////////////////////////////?

//??業(yè)務(wù)邏輯類?
//??Client?現(xiàn)在只需要繼承?INetWorkRecvable?即可

/**/////////////////////////////////////////////////////////////////////////////////?
class??Client?:?public?INetWorkRecvable


{
public?:
????Client()

????
{
????????m_pClientObserver?=?NULL;
????????m_plog?=?NULL;
????????m_pSendable?=?NULL;
????}


????virtual??~Client()?
{}
????

????void??registerObserver(ClientObserver?*??p)???
{?m_pClientObserver??=??p;?}?

????void??removeObserver()???
{?m_pClientObserver??=??NULL;?}?
????

????void??setLoger(ILogable?*??p)???
{?m_plog??=??p;?}?

????void??removeLoger()???????????
{?m_plog??=??NULL;?}?
????

????void??setSendable(INetWorkSendable*?p)?
{?m_pSendable?=?p;?}

????void??removeSendable(INetWorkSendable*?p)?
{?m_pSendable?=?NULL;?}
?
????bool?SendLogin(const?char*?name,??const?char*?pwd)

????
{
????????tagClientLogin?login;
????????memset(?&?login,??0?,??sizeof?(login));
????????login.header.nCmd??=??NETWORK_CMD_LOGIN;
????????strncpy(login.username,?name,??sizeof?(login.username));????????
????????strncpy(login.userpwd,?pwd,??sizeof?(login.userpwd));

????????//?Sendable?改成了?"組合"?的方式后,每次調(diào)用?Send?都要判斷,?讓我很不爽
????????if(?m_pSendable?!=?NULL?)

????????
{
????????????return?m_pSendable->send(&login,??sizeof?(login));
????????}
????????else

????????
{
????????????return?false;
????????}
????}?
????
protected?:????
????virtual?int?onreceive(?const???void?*??pvoid,??int??nSize)

????
{
????????if??(?nSize??<???sizeof?(cmd)?)
????????????return???0?;
????????
????????cmd?*??pheader??=??(cmd?*?)pvoid;
????????
????????if??(?pheader?->?nCmd??==??NETWORK_CMD_REP_LOGIN?)

????????
{
????????????if??(?nSize??<???sizeof?(tagRepClientLogin)?)
????????????????return???0?;
????????????
????????????tagRepClientLogin?*??ptagRepClientLogin??=??(tagRepClientLogin?*?)pvoid;
????????????
????????????if??(?m_pClientObserver??!=??NULL?)
????????????????m_pClientObserver?->?onRepLogin(ptagRepClientLogin?->?bLoginSuccess);
????????????
????????????return???sizeof?(tagRepClientLogin);????
????????}?
????????
????????return???0?;
????}?
????
private?:
????ClientObserver?*??m_pClientObserver;
????ILogable?*????????m_plog;
????INetWorkSendable*?m_pSendable;
}?;?
測試?yán)?br />
#include?"client.h"
#include?<string.h>

class?testClient?:?public?Client,?INetWorkSendable


{
public:

????testClient()??
{?memset(m_buf,?0,?sizeof(m_buf));?}

????~testClient()?
{}
????????
????int?NetWorkReceive(const?void*?pvoid,?int?nSize)

????
{
????????return?onreceive(pvoid,?nSize);
????}

????virtual?bool??send(const???void?*??pvoid,??int??nSize)

????
{
????????copyMemory(pvoid,?nSize);
????????return?true;
????}
????
????bool?cmpMemory(const?void*?pvoid,?int?nSize)

????
{
????????return?(?0?==?memcmp(m_buf,?pvoid,?nSize)?);
????}
????
????void?copyMemory(const?void*?pvoid,?int?nSize)

????
{
????????memcpy(m_buf,?pvoid,?nSize);
????}

private:
????char?m_buf[1024];
};

int?main()


{
????testClient?test;
????test.setSendable((INetWorkSendable*)&test);

????test.SendLogin("test_username",?"test_pwd");
????
????tagClientLogin?clientlogin;
????memset(&clientlogin,?0,?sizeof(clientlogin));
????clientlogin.header.nCmd?=?NETWORK_CMD_LOGIN;
????strcpy(clientlogin.username,?"test_username");
????strcpy(clientlogin.userpwd,??"test_pwd");
????if(?!test.cmpMemory(&clientlogin,?sizeof(clientlogin))?)
????????cout?<<?"test?failed"?<<?endl;
????

????char?szBuf[1024]??=?
{0};
????
????//?摸擬服務(wù)器發(fā)送的包長度不足
????if(?0?!=?test.NetWorkReceive(szBuf,?sizeof(tagRepClientLogin)?-?10)?)
????????cout?<<?"test?failed"?<<?endl;
????
????//?摸擬服務(wù)器發(fā)送的包內(nèi)容非法
????if(?0?!=?test.NetWorkReceive(szBuf,?sizeof(tagRepClientLogin))?)
????????cout?<<?"test?failed"?<<?endl;
????
????tagRepClientLogin?repLogin;
????repLogin.header.nCmd?=?NETWORK_CMD_REP_LOGIN;
????memcpy(szBuf,?&repLogin,?sizeof(repLogin));
????
????//?摸擬服務(wù)器發(fā)送了正確的包
????if(?sizeof(tagRepClientLogin)?!=?test.NetWorkReceive(szBuf,?sizeof(tagRepClientLogin))?)
????????cout?<<?"test?failed"?<<?endl;
????
????return?0;
}
#include?<windows.h>
#include?<iostream>
using?namespace?std;
//??網(wǎng)絡(luò)通信協(xié)議?
/**///////////////////////////////////////////////////////////////////////////////?//?
struct?cmd

{
????int?nCmd;
};
#pragma?pack(1)
struct??tagClientLogin

{
????cmd??header;
????char??username[?20?];
????char??userpwd[?20?];
}?;
struct??tagRepClientLogin

{
????cmd??header;
????bool??bLoginSuccess;
};
#pragma?pack(1)
#define??NETWORK_CMD_LOGIN?1?
#define??NETWORK_CMD_REP_LOGIN?2?
/**/////////////////////////////////////////////////////////////////////////////////?
//??接口定義?
/**/////////////////////////////////////////////////////////////////////////////////?
class??ClientObserver

{
public?:
????ClientObserver()???
{}?
????~?ClientObserver()?
{}?
????
????virtual?void?onRepLogin(?bool??bLoginSuccess)??=???0?;
}?;

/**//*
class?INetWorkable
{
public?:
????INetWorkable()??{}?
????~INetWorkable()?{}?
????
????//??pvoid?:?欲發(fā)送的緩沖區(qū);?nSize?:?緩沖區(qū)的大小?
????virtual?bool??send(?const???void?*??pvoid,??int??nSize)?=?0?;
????
????//??由網(wǎng)絡(luò)層調(diào)用,pvoid:?接收到的數(shù)據(jù)的緩沖區(qū),?nSize?:?緩沖區(qū)的大小;??返回已經(jīng)處理的數(shù)據(jù)長度?
????virtual?int?onreceive(?const???void?*??pvoid,??int??nSize)?=?0?;
};
*/
//?將原先的?INetWorkable?接口拆分成兩個類
class?INetWorkSendable

{
public?:
????INetWorkSendable()??
{}?
????~INetWorkSendable()?
{}?
????
????//??pvoid?:?欲發(fā)送的緩沖區(qū);?nSize?:?緩沖區(qū)的大小?
????virtual?bool??send(?const???void?*??pvoid,??int??nSize)?=?0?;
};
class?INetWorkRecvable

{
public?:
????INetWorkRecvable()??
{}?
????~INetWorkRecvable()?
{}?
????
????//??由網(wǎng)絡(luò)層調(diào)用,pvoid:?接收到的數(shù)據(jù)的緩沖區(qū),?nSize?:?緩沖區(qū)的大小;??返回已經(jīng)處理的數(shù)據(jù)長度?
????virtual?int?onreceive(?const???void?*??pvoid,??int??nSize)?=?0?;
};
class?ILogable

{
public?:
????ILogable()???
{}?
????~?ILogable()???
{}?
????
????virtual?void?log(const?char*?plog)?=?0;
};
/**/////////////////////////////////////////////////////////////////////////////////?
//??業(yè)務(wù)邏輯類?
//??Client?現(xiàn)在只需要繼承?INetWorkRecvable?即可
/**/////////////////////////////////////////////////////////////////////////////////?
class??Client?:?public?INetWorkRecvable

{
public?:
????Client()
????
{
????????m_pClientObserver?=?NULL;
????????m_plog?=?NULL;
????????m_pSendable?=?NULL;
????}

????virtual??~Client()?
{}
????
????void??registerObserver(ClientObserver?*??p)???
{?m_pClientObserver??=??p;?}?
????void??removeObserver()???
{?m_pClientObserver??=??NULL;?}?
????
????void??setLoger(ILogable?*??p)???
{?m_plog??=??p;?}?
????void??removeLoger()???????????
{?m_plog??=??NULL;?}?
????
????void??setSendable(INetWorkSendable*?p)?
{?m_pSendable?=?p;?}
????void??removeSendable(INetWorkSendable*?p)?
{?m_pSendable?=?NULL;?}
?
????bool?SendLogin(const?char*?name,??const?char*?pwd)
????
{
????????tagClientLogin?login;
????????memset(?&?login,??0?,??sizeof?(login));
????????login.header.nCmd??=??NETWORK_CMD_LOGIN;
????????strncpy(login.username,?name,??sizeof?(login.username));????????
????????strncpy(login.userpwd,?pwd,??sizeof?(login.userpwd));
????????//?Sendable?改成了?"組合"?的方式后,每次調(diào)用?Send?都要判斷,?讓我很不爽
????????if(?m_pSendable?!=?NULL?)
????????
{
????????????return?m_pSendable->send(&login,??sizeof?(login));
????????}
????????else
????????
{
????????????return?false;
????????}
????}?
????
protected?:????
????virtual?int?onreceive(?const???void?*??pvoid,??int??nSize)
????
{
????????if??(?nSize??<???sizeof?(cmd)?)
????????????return???0?;
????????
????????cmd?*??pheader??=??(cmd?*?)pvoid;
????????
????????if??(?pheader?->?nCmd??==??NETWORK_CMD_REP_LOGIN?)
????????
{
????????????if??(?nSize??<???sizeof?(tagRepClientLogin)?)
????????????????return???0?;
????????????
????????????tagRepClientLogin?*??ptagRepClientLogin??=??(tagRepClientLogin?*?)pvoid;
????????????
????????????if??(?m_pClientObserver??!=??NULL?)
????????????????m_pClientObserver?->?onRepLogin(ptagRepClientLogin?->?bLoginSuccess);
????????????
????????????return???sizeof?(tagRepClientLogin);????
????????}?
????????
????????return???0?;
????}?
????
private?:
????ClientObserver?*??m_pClientObserver;
????ILogable?*????????m_plog;
????INetWorkSendable*?m_pSendable;
}?;?測試?yán)?br />
#include?"client.h"
#include?<string.h>
class?testClient?:?public?Client,?INetWorkSendable

{
public:
????testClient()??
{?memset(m_buf,?0,?sizeof(m_buf));?}
????~testClient()?
{}
????????
????int?NetWorkReceive(const?void*?pvoid,?int?nSize)
????
{
????????return?onreceive(pvoid,?nSize);
????}
????virtual?bool??send(const???void?*??pvoid,??int??nSize)
????
{
????????copyMemory(pvoid,?nSize);
????????return?true;
????}
????
????bool?cmpMemory(const?void*?pvoid,?int?nSize)
????
{
????????return?(?0?==?memcmp(m_buf,?pvoid,?nSize)?);
????}
????
????void?copyMemory(const?void*?pvoid,?int?nSize)
????
{
????????memcpy(m_buf,?pvoid,?nSize);
????}
private:
????char?m_buf[1024];
};
int?main()

{
????testClient?test;
????test.setSendable((INetWorkSendable*)&test);
????test.SendLogin("test_username",?"test_pwd");
????
????tagClientLogin?clientlogin;
????memset(&clientlogin,?0,?sizeof(clientlogin));
????clientlogin.header.nCmd?=?NETWORK_CMD_LOGIN;
????strcpy(clientlogin.username,?"test_username");
????strcpy(clientlogin.userpwd,??"test_pwd");
????if(?!test.cmpMemory(&clientlogin,?sizeof(clientlogin))?)
????????cout?<<?"test?failed"?<<?endl;
????
????char?szBuf[1024]??=?
{0};
????
????//?摸擬服務(wù)器發(fā)送的包長度不足
????if(?0?!=?test.NetWorkReceive(szBuf,?sizeof(tagRepClientLogin)?-?10)?)
????????cout?<<?"test?failed"?<<?endl;
????
????//?摸擬服務(wù)器發(fā)送的包內(nèi)容非法
????if(?0?!=?test.NetWorkReceive(szBuf,?sizeof(tagRepClientLogin))?)
????????cout?<<?"test?failed"?<<?endl;
????
????tagRepClientLogin?repLogin;
????repLogin.header.nCmd?=?NETWORK_CMD_REP_LOGIN;
????memcpy(szBuf,?&repLogin,?sizeof(repLogin));
????
????//?摸擬服務(wù)器發(fā)送了正確的包
????if(?sizeof(tagRepClientLogin)?!=?test.NetWorkReceive(szBuf,?sizeof(tagRepClientLogin))?)
????????cout?<<?"test?failed"?<<?endl;
????
????return?0;
}

