前面一段时间在宠物模块重构的时候,惊叹这个模块的好几个函数长度居然有达到3000行,在重构这块的时候用,利用函数指针写了一个小的工具模板。函数指针与成员函数指针,在一些进阶应用中时有涉及,比如常见的EventMap,这里介绍一个经常用成员函数指针来对长长switch的进行的重构手法。
先简单的说明一下函数指针与成员函数指针:
#include<iostream> class CPlusPlus_Class;
//声明了一个函数指针类型 pfnHandle_C, 这个函数返回void,参数也是void typedef void (*pfnHandle_C)(void);
//声明了一个成员函数指针类型 pfnHandle_CPP,这个函数是 CPlusPlus_Class 类的成员函数,返回void,参数也是void typedef void (CPlusPlus_Class::*pfnHandle_CPP)(void); void egFunc_C(void) { //output egFunc_C std::cout<<"egFunc_C"<<std::endl; } class CPlusPlus_Class { public: void egFunc_CPP(void) { //output egFunc_CPP std::cout<<"CPlusPlus_Class::egFunc_CPP"<<std::endl; }; } int _tmain(int argc, _TCHAR* argv[]) { pfnHandle_C pfn_C_VV = egFunc_C; egFunc_C() pfn_C_VV(); CPlusPlus_Class objCpp; pfnHandle_CPP pfn_CPP_VV = &CPlusPlus_Class::egFunc_CPP; objCpp.egFunc_CPP(); (objCpp.*pfn_CPP_VV)(); }
在一个初始的设计当中,往往容易出现如下的函数结构:
int CPlusPlus_Class::eventHandle(int eventChoice, int lfsParam, int rfsParam)
{ int nRet = E_SYS_SUCCESS; // Do some thing //............. swithc(eventChoice) { case E_EVENT_CHOICE_A: // 1 { } break; case E_EVENT_CHOICE_B: // 2 { } break; case E_EVENT_CHOICE_C: // 3 { } break; case E_EVENT_CHOICE_D: // 4 { } break; case E_EVENT_CHOICE_E: // 5 { } break; } return nRet; }
在开始的时候,这个结构还是相当的美观的,随着开发的深入,这个函数增长超出你的想象,而且结构越来越混乱,哪些该放在switch里面 ,哪些改放在 switch前面,哪些该放在switch后面,也让你越来越纠结。在工作当中,我接手的一个模块就很多地方有这种冗长的接口,记得一个处理宠物使用道具的接口,总共有15个switch分支(总共有15种道具可对宠物使用),接口函数的总长度达到3568行,全部是逻辑代码,这个函数从前面看到后面最终也不知道自己再看什么了。为了分解这个接口,用了一个函数指针表来存储入口,然后根据选项计算接口地址。最终用模板来表达这个概念,在同一个类里面把算法封装到各个子接口,然后把算法子接口存储在一张表里面,根据选择项调用不同的算法接口。
template <class HandleClass, class EventReceiver> class IClassFunctionMap { public: typedef int (HandleClass::*pfnEventHandle)(EventReceiver* pReceiver, int nParam1, int nParam2, int nParam3, int nParam4, const char* pszChar); typedef std::map<int, typename IClassFunctionMap::pfnEventHandle > EventHandleMap; typedef typename EventHandleMap::iterator EventHandleMapIter; typedef typename EventHandleMap::const_iterator EventHandleMapConstIter; virtual int AddEventHandle(int nChoice, pfnEventHandle pfnHandle) { m_HandleMap[nChoice] = pfnHandle; return COMMONUTIL_SUCCE; } virtual int DelEventHandle(int nChoice) { pfnEventHandle pfnHandle = FindEventHandle(nChoice); if (pfnHandle) { m_HandleMap.erase(nChoice); } return COMMONUTIL_SUCCE; } virtual int DoEventHandle(int nChoice, EventReceiver* pReceiver, int nParam1, int nParam2, int nParam3, int nParam4, const char* pszChar) { const pfnEventHandle pfnHandle = FindEventHandle(nChoice); if (pfnHandle) { HandleClass* pHandClass = static_cast<HandleClass*>(this); if (pHandClass) { (pHandClass->*pfnHandle)(pReceiver, nParam1, nParam2, nParam3, nParam4, pszChar); return COMMONUTIL_SUCCE; } } return COMMONUTIL_ERROR; } protected: virtual pfnEventHandle FindEventHandle(int nChoice)const { EventHandleMapConstIter ite = m_HandleMap.find(nChoice); if (ite != m_HandleMap.end()) { return ite->second; } return NULL; } private: EventHandleMap m_HandleMap; }; class ExEventHandleFromInt : public IClassFunctionMap<ExEventHandleFromInt, int> { public: int ExEventHandle_1(int* pRe, int Param1, int Param2, int Param3, int Param4, const char* pszChar) { std::cout<<"ExEventHandle_1 : "<<Param1<<std::endl; return 1; } int ExEventHandle_2(int* pRe, int Param1, int Param2, int Param3, int Param4, const char* pszChar) { std::cout<<"ExEventHandle_2 : "<<Param1<<std::endl; return 1; } int ExEventHandle_3(int* pRe, int Param1, int Param2, int Param3, int Param4, const char* pszChar) { std::cout<<"ExEventHandle_3 : "<<Param1<<std::endl; return 1; } int ExEventHandle_4(int* pRe, int Param1, int Param2, int Param3, int Param4, const char* pszChar) { std::cout<<"ExEventHandle_4 : "<<Param1<<std::endl; return 1; } protected: private: }; #define OUTPUT_SEPARATOR " " int _tmain(int argc, _TCHAR* argv[]) { ExEventHandleFromInt stExHandle; stExHandle.AddEventHandle(1, &ExEventHandleFromInt::ExEventHandle_1); stExHandle.AddEventHandle(2, &ExEventHandleFromInt::ExEventHandle_2); stExHandle.AddEventHandle(3, &ExEventHandleFromInt::ExEventHandle_3); stExHandle.AddEventHandle(4, &ExEventHandleFromInt::ExEventHandle_4); stExHandle.DoEventHandle(1, NULL, 1, 2, 3, 4, NULL); stExHandle.DoEventHandle(2, NULL, 1, 2, 3, 4, NULL); stExHandle.DoEventHandle(3, NULL, 1, 2, 3, 4, NULL); stExHandle.DoEventHandle(4, NULL, 1, 2, 3, 4, NULL); stExHandle.DoEventHandle(5, NULL, 1, 2, 3, 4, NULL); stExHandle.DelEventHandle(1); stExHandle.DelEventHandle(3); stExHandle.DoEventHandle(1, NULL, 1, 2, 3, 4, NULL); stExHandle.DoEventHandle(2, NULL, 1, 2, 3, 4, NULL); stExHandle.DoEventHandle(3, NULL, 1, 2, 3, 4, NULL); stExHandle.DoEventHandle(4, NULL, 1, 2, 3, 4, NULL); stExHandle.AddEventHandle(1, &ExEventHandleFromInt::ExEventHandle_4); stExHandle.AddEventHandle(3, &ExEventHandleFromInt::ExEventHandle_4); stExHandle.DoEventHandle(1, NULL, 1, 2, 3, 4, NULL); stExHandle.DoEventHandle(2, NULL, 1, 2, 3, 4, NULL); stExHandle.DoEventHandle(3, NULL, 1, 2, 3, 4, NULL); stExHandle.DoEventHandle(4, NULL, 1, 2, 3, 4, NULL); system("pause"); return 0; }
上面代码中可以非常清晰的看到用一个IClassFunctionMap::DoEventHandle接口处理策略分配。而具体的处理工作都分布在ExEventHandle_1 , ExEventHandle_2...中,而且这个策略是一个动态变化的,
可以在需要的时候通过接口IClassFunctionMap::AddEventHandle和接口IClassFunctionMap::DelEventHandle改写策略map,
后记,上面的实现可以考虑用一个固定大小的数组来替代map(C++虚函数表就是一个127的数组),优化执行效率。
Sign, Clown , 2010.06.30 . 19:45 . HDPY
[本文原创,转载请注明出处,在文章末尾提供原文链接http://www.cnblogs.com/JefferyZhou/,否则一旦发现,将按字节每人民币收费,绝不论价]