C++使用模板进行的一种重构
如果有一些遗留代码,里面有很多结构,定义了一些相同的成员,但在一些时候,需要取出这些成员,进行同样的处理。如下面这些代码的红色部分。
——原先的程序结构是使用类型码来区分实际的类型,客观地说,这些遗留代码是比较混乱的。
不想说太多,用简单的代码来说明问题吧。
typedef struct _EVT_SWITCH : public EVT_HEAD {
DWORD dwCategory;
DWORD dwSeverity;
DWORD dwEvtSrcID;
DWORD dwEvtSrcOffset;
DWORD dwSrcIp;
DWORD dwSrcPort;
DWORD dwDstIp;
DWORD dwDstPort;
DWORD dwProtocol;
DWORD dwEvtUserOffset;
DWORD dwEvtUserIp;
DWORD dwStatus;
DWORD dwOp;
DWORD dwEvtNum;
DWORD dwDetailOffset;
CHAR szContent[0];
}EVT_SWITCH,*PEVT_SWITCH;
typedef struct _EVT_ROUTER : public EVT_HEAD {
DWORD dwCategory;
DWORD dwSeverity;
DWORD dwEvtSrcID;
DWORD dwEvtSrcOffset;
DWORD dwSrcIp;
DWORD dwSrcPort;
DWORD dwDstIp;
DWORD dwDstPort;
DWORD dwProtocol;
DWORD dwEvtUserOffset;
DWORD dwEvtUserIp;
DWORD dwStatus;
DWORD dwOp;
DWORD dwEvtNum;
DWORD dwDetailOffset;
CHAR szContent[0];
}EVT_ROUTER,*PEVT_ROUTER;
typedef struct _EVT_NETWORK : public EVT_HEAD {
DWORD dwCategoryOffset;
DWORD dwSeverity;
DWORD dwEvtId;
DWORD dwEvtSrcOffset;
DWORD dwEvtUserOffset;
DWORD dwEvtTypeOffset;
DWORD dwSrcIp;
DWORD dwSrcPort;
DWORD dwDstIp;
DWORD dwDstPort;
DWORD dwProtocol;
DWORD dwSmacOffset;
DWORD dwDmacOffset;
DWORD dwFlagOffset;
DDWORD ddwInB,ddwOutB,ddwInPkt,ddwOutPkt;
DDWORD ddwSessionId;
DWORD dwRuleOffset;
DWORD dwStatusOffset;
DWORD dwOpOffset;
DWORD dwReasonOffset;
int tDuration;
DWORD dwEvtNum;
DWORD dwArgOffset;
DWORD dwMsgOffset;
DWORD dwDetailOffset;
CHAR szContent[0];
}EVT_FW,*PEVT_FW,EVT_NETWORK,*PEVT_NETWORK;
typedef struct _EVT_VPN : public EVT_HEAD {
int tDuration;
DWORD dwCategoryOffset;
DWORD dwSeverity;
DWORD dwEvtId;
DWORD dwEvtSrcOffset;
DWORD dwEvtUserOffset;
DWORD dwEvtTypeOffset;
DWORD dwDevActionOffset;
DWORD dwDevMoudleNameOffset;
DWORD dwServiceOffset;
DWORD dwSrcIp;
DWORD dwSrcPort;
DWORD dwDstIp;
DWORD dwDstPort;
DWORD dwProtocol;
DWORD dwSmacOffset;
DWORD dwDmacOffset;
DWORD dwTargetUserIDOffset;
DWORD dwTargetDomainOffset;
DWORD dwMessageIDOffset;
DWORD dwTunnelOffset;
DWORD dwInterfaceOffset;
DWORD dwMmemonicOffset;
DWORD dwFlagOffset;
DDWORD ddwInB,ddwOutB,ddwInPkt,ddwOutPkt;
DDWORD ddwSessionId;
DWORD dwStatusOffset;
DWORD dwOpOffset;
DWORD dwReasonOffset;
DWORD dwEvtNum;
DWORD dwArgOffset;
DWORD dwMsgOffset;
DWORD dwDetailOffset;
CHAR szContent[0];
}EVT_VPN,*PEVT_VPN;
typedef struct _EVT_SECURE : public EVT_HEAD {
DWORD dwCategoryOffset;
DWORD dwSeverity;
DWORD dwEvtTypeOffset;
DWORD dwEvtSrcOffset;
DWORD dwEvtUserOffset;
DWORD dwSrcIp;
DWORD dwSrcPort;
DWORD dwDstIp;
DWORD dwDstPort;
DWORD dwProtocol;
DWORD dwFlagOffset;
DDWORD ddwInB,ddwOutB,ddwInPkt,ddwOutPkt;
DDWORD ddwSessionId;
DWORD dwRuleOffset;
DWORD dwStatusOffset;
DWORD dwOpOffset;
DWORD dwReasonOffset;
DWORD dwEvtId;
DWORD dwEvtNum;
DWORD dwSignatureOffset;
DWORD dwDetailOffset;
CHAR szContent[0];
}EVT_SECURE,*PEVT_SECURE;
这些类型实际上是同一类类型,实际上可以从同一个类派生,使用 PullUp Member 方法重构。但是这些结构已经发布,不可能施行这种重构。可以这样:
class CEventWrapper
{
public:
CEventWrapper(PEVT_HEAD p) { m_p = p; }
struct NetInfo
{
DWORD dwDstIp;
DWORD dwDstPort;
DWORD dwSrcIp;
DWORD dwSrcPort;
DWORD dwProtocol;
TCHAR szDstMac[20];
TCHAR szSrcMac[20];
};
BOOL GetNetInfo(NetInfo* p) const;
template
TemplateGetNetInfo(CEventWrapper::NetInfo* netInfo, const T& x)
{
netInfo->dwDstIp = x.dwDstIp;
netInfo->dwDstPort = x.dwDstPort;
netInfo->dwSrcIp = x.dwSrcIp;
netInfo->dwSrcPort = x.dwSrcPort;
netInfo->dwProtocol = x.dwProtocol;
}
BOOL HasNetInfo() const;
private:
PEVT_HEAD m_p;
};
BOOL CEventWrapper::HasNetInfo() const
{
NetInfo ni;
return GetNetInfo(&ni);
}
BOOL CEventWrapper::GetNetInfo(NetInfo* netInfo) const
{
memset(netInfo, 0, sizeof(NetInfo));
switch (m_p->dwLogFrt)
{
default:
ASSERT(0);
return FALSE;
case DIAL_LOG:
case WEBTRENDS_LOG:
case SNORT_LOG:
case SENDMAIL_LOG:
case SYSLOG:
case NETSCREEN_LOG:
case WIN_FILE_LOG:
case WIN_PROCESS_LOG:
case APACHE_ERROR_LOG:
case IP_MON_LOG:
case IP_UP_LOG:
case PROC_MON_LOG:
case GENERAL_MON_LOG:
case PERF_MON_LOG:
case PORTMON_LOG:
ASSERT(0);
return FALSE;
case EVENT_LOG: return FALSE;
case CP_LOG:
TemplateGetNetInfo(netInfo, *(EVT_VIRUS*)(m_p + 1));
return TRUE;
case VPN_LOG:
TemplateGetNetInfo(netInfo, *(EVT_VPN*)(m_p + 1));
return TRUE;
case SECEXPERT_LOG: return FALSE;
case IIS_FTP_LOG: return FALSE;
case EXCHANGE_LOG: return FALSE;
case FW_LOG:
{
EVT_FW* p = (EVT_FW*)(m_p + 1);
TemplateGetNetInfo(netInfo, *p);
if (p->dwDmacOffset)
lstrcpyn(netInfo->szDstMac, p->dwDmacOffset + (char*)p,
dimof(netInfo->szDstMac));
if (p->dwSmacOffset)
lstrcpyn(netInfo->szSrcMac, p->dwSmacOffset + (char*)p,
dimof(netInfo->szSrcMac));
return TRUE;
}
case DOMINO_HTTP_LOG:
case APACHE_LOG:
case IIS_HTTP_LOG:
return FALSE;
case CISCO_PIX_LOG:
case CISCO_IOS_LOG:
case CISCO_SWITCH_LOG:
case HUAWEI_SWITCH_LOG:
case NORTEL_SWITCH_LOG:
TemplateGetNetInfo(netInfo, *(EVT_SWITCH*)(m_p + 1));
return TRUE;
case SQLSERVER_LOG:
case ORACLE_LOG:
case MYSQL_LOG:
return FALSE;
case KIDS_LOG: case IDS_LOG:
TemplateGetNetInfo(netInfo, *(EVT_SECURE*)(m_p + 1));
return TRUE;
}
ASSERT(0);
return FALSE;
}