再谈谈注冊(本质是建立映射)与回调
在之前的博文中, 我们探讨过映射的重要作用。 请直接看:http://blog.csdn.net/stpeace/article/details/39452203, 在那篇文章中, 我们是用STL中的map来做的, map建立的是key-value映射, 在本文中, 我们自己来建立映射, 并讨论一个更为复杂的程序, 顺便再次复习一下注冊与回调。
注冊与回调? 有那么复杂么?没有必要过多地扯了, 直接上代码:
#include <iostream> #include <vector> using namespace std; // 前向声明 class BasicMod; //类函数指针类型 typedef void (BasicMod:: *PFun)(const char* pParaName); // 映射结点 typedef struct { BasicMod *pMod; char szParaName[1024]; PFun operTypeOne; PFun operTypeTwo; PFun operTypeThree; }MyMap; // 用全局的g_pv保存结点指针 vector<MyMap *> g_pv; // 运行类, 提供注冊, 查找接口, 并运行回调操作 class Do { public: // 单例 static Do *getInstance() { static Do *p = NULL; if(NULL == p) { p = new Do; } return p; } // 注冊接口 void regNode(BasicMod *pb, MyMap *pmap, int i) { MyMap *p = new MyMap; p->pMod = pb; memset(p->szParaName, 0, sizeof(p->szParaName)); strncpy(p->szParaName, (pmap + i)->szParaName, sizeof(p->szParaName) - 1); p->operTypeOne = (pmap + i)->operTypeOne; p->operTypeTwo = (pmap + i)->operTypeTwo; p->operTypeThree = (pmap + i)->operTypeThree; g_pv.push_back(p); } // 查找接口 MyMap *findNode(const char *pParaName) { int n = g_pv.size(); int i = 0; for(i = 0; i < n; i++) { if(0 == strcmp(g_pv[i]->szParaName, pParaName)) { return g_pv[i]; } } return NULL; } // 运行回调操作 void exect(const char *pParaName) { MyMap *p = findNode(pParaName); if(NULL != p && NULL != p->pMod) { ((p->pMod)->*(p->operTypeOne))(pParaName); ((p->pMod)->*(p->operTypeTwo))(pParaName); ((p->pMod)->*(p->operTypeThree))(pParaName); } } }; // 基类 class BasicMod { public: void reg(BasicMod *pm, MyMap *p, int i) { Do::getInstance()->regNode(pm, p, i); } }; // 格式化 #define TOGETHER(mod, name, f1, f2, f3) {NULL, name, (PFun)(&mod::f1), (PFun)(&mod::f2), (PFun)(&mod::f3)} // 模块1 class Mod1 : public BasicMod { public: static Mod1* getInstance() { static Mod1* p = NULL; if(NULL == p) { p = new Mod1; } return p; } // 模块1的初始化 void init() { MyMap mapArr[] = { TOGETHER(Mod1, "cpu", fun1Cpu, fun2Cpu, fun3Cpu), }; int n = sizeof(mapArr) / sizeof(mapArr[0]); int i = 0; for(i = 0; i < n; i++) { // 注冊 reg(getInstance(), mapArr, i); } } // 提供回调接口 void fun1Cpu(const char *pParaName) { cout << "mod1, pParaName is " << pParaName << endl; } // 提供回调接口 void fun2Cpu(const char *pParaName) { cout << "mod1, pParaName is " << pParaName << endl; } // 提供回调接口 void fun3Cpu(const char *pParaName) { cout << "mod1, pParaName is " << pParaName << endl; } }; class Mod2 : public BasicMod { public: static Mod2* getInstance() { static Mod2* p = NULL; if(NULL == p) { p = new Mod2; } return p; } void init() { MyMap mapArr[] = { TOGETHER(Mod2, "flash", fun1Flash, fun2Flash, fun3Flash), }; int n = sizeof(mapArr) / sizeof(mapArr[0]); int i = 0; for(i = 0; i < n; i++) { reg(getInstance(), mapArr, i); } } void fun1Flash(const char *pParaName) { cout << "mod2, pParaName is " << pParaName << endl; } void fun2Flash(const char *pParaName) { cout << "mod2, pParaName is " << pParaName << endl; } void fun3Flash(const char *pParaName) { cout << "mod2, pParaName is " << pParaName << endl; } }; int main() { // 模块初始化 Mod1::getInstance()->init(); Mod2::getInstance()->init(); // 运行操作 Do::getInstance()->exect("cpu"); Do::getInstance()->exect("flash"); Do::getInstance()->exect("mem"); return 0; }程序的结果为:
mod1, pParaName is cpu
mod1, pParaName is cpu
mod1, pParaName is cpu
mod2, pParaName is flash
mod2, pParaName is flash
mod2, pParaName is flash
我们也能够对上述程序作一下等价变换, 得到:
#include <iostream> #include <vector> using namespace std; // 前向声明 class BasicMod; //类函数指针类型 typedef void (BasicMod:: *PFun)(const char* pParaName); // 映射结点 typedef struct { BasicMod *pMod; char szParaName[1024]; PFun operTypeOne; PFun operTypeTwo; PFun operTypeThree; }MyMap; // 用全局的g_pv保存结点指针 vector<MyMap *> g_pv; // 运行类, 提供注冊, 查找接口, 并运行回调操作 class Do { public: // 单例 static Do *getInstance() { static Do *p = NULL; if(NULL == p) { p = new Do; } return p; } // 注冊接口 void regNode(BasicMod *pm, const char *pParaName, PFun one, PFun two, PFun three) { MyMap *p = new MyMap; p->pMod = pm; memset(p->szParaName, 0, sizeof(p->szParaName)); strncpy(p->szParaName, pParaName, sizeof(p->szParaName) - 1); p->operTypeOne = one; p->operTypeTwo = two; p->operTypeThree = three; g_pv.push_back(p); } // 查找接口 MyMap *findNode(const char *pParaName) { int n = g_pv.size(); int i = 0; for(i = 0; i < n; i++) { if(0 == strcmp(g_pv[i]->szParaName, pParaName)) { return g_pv[i]; } } return NULL; } // 运行回调操作 void exect(const char *pParaName) { MyMap *p = findNode(pParaName); if(NULL != p && NULL != p->pMod) { ((p->pMod)->*(p->operTypeOne))(pParaName); ((p->pMod)->*(p->operTypeTwo))(pParaName); ((p->pMod)->*(p->operTypeThree))(pParaName); } } }; // 基类 class BasicMod { public: void reg(const char *pParaName, PFun one, PFun two, PFun three) { Do::getInstance()->regNode(this, pParaName, one, two, three); } }; // 格式化 #define TOGETHER(mod, name, f1, f2, f3) {NULL, name, (PFun)(&mod::f1), (PFun)(&mod::f2), (PFun)(&mod::f3)} // 模块1 class Mod1 : public BasicMod { public: static Mod1* getInstance() { static Mod1* p = NULL; if(NULL == p) { p = new Mod1; } return p; } // 模块1的初始化 void init() { MyMap mapArr[] = { TOGETHER(Mod1, "cpu", fun1Cpu, fun2Cpu, fun3Cpu), }; int n = sizeof(mapArr) / sizeof(mapArr[0]); int i = 0; for(i = 0; i < n; i++) { // 注冊 reg(mapArr[i].szParaName, mapArr[i].operTypeOne, mapArr[i].operTypeTwo, mapArr[i].operTypeThree); } } // 提供回调接口 void fun1Cpu(const char *pParaName) { cout << "mod1, pParaName is " << pParaName << endl; } // 提供回调接口 void fun2Cpu(const char *pParaName) { cout << "mod1, pParaName is " << pParaName << endl; } // 提供回调接口 void fun3Cpu(const char *pParaName) { cout << "mod1, pParaName is " << pParaName << endl; } }; class Mod2 : public BasicMod { public: static Mod2* getInstance() { static Mod2* p = NULL; if(NULL == p) { p = new Mod2; } return p; } void init() { MyMap mapArr[] = { TOGETHER(Mod2, "flash", fun1Flash, fun2Flash, fun3Flash), }; int n = sizeof(mapArr) / sizeof(mapArr[0]); int i = 0; for(i = 0; i < n; i++) { reg(mapArr[i].szParaName, mapArr[i].operTypeOne, mapArr[i].operTypeTwo, mapArr[i].operTypeThree); } } void fun1Flash(const char *pParaName) { cout << "mod2, pParaName is " << pParaName << endl; } void fun2Flash(const char *pParaName) { cout << "mod2, pParaName is " << pParaName << endl; } void fun3Flash(const char *pParaName) { cout << "mod2, pParaName is " << pParaName << endl; } }; int main() { // 模块初始化 Mod1::getInstance()->init(); Mod2::getInstance()->init(); // 运行操作 Do::getInstance()->exect("cpu"); Do::getInstance()->exect("flash"); Do::getInstance()->exect("mem"); return 0; }
我们看到, 上述程序建立了一个name对于{f1, f2, f3}的映射。 适用范围更广。
并且, 以后假设再加字段。 程序员仅仅须要注意三处就可以: 1. 添加initialize函数中数组中的项(添加映射);2. 在类中实现回调接口(添加回调接口); 3.在main中启动调用(启动运行)。
当然啦, 假设要添加模块3, 那也是非常easy的。
反思一下:我突然发现。 我把上面的程序写复杂了。 事实上, 也能够用STL map建立name到f1, f2, f3的映射, 此时, 要把{f1, f2, f3}看成一个总体, 上述程序用STL map进行改造后,
会更好, 有兴趣的朋友能够试试。 我相信: 一次刻骨铭心的体验胜过千百次说教。