命令调度机制
1 #pragma once 2 3 #include <vector> 4 #include <iostream> 5 #include <functional> 6 using namespace std; 7 8 class CMD; 9 typedef function<void(CMD*)> CmdHandler; 10 #define CMD_HANDLER(CLASS_NAME,FUNC_NAME) bind(&CLASS_NAME::FUNC_NAME,this,placeholders::_1) 11 12 class CMD{ 13 public: 14 inline int getID(){ 15 return mID; 16 } 17 18 //注册命令处理器 19 static void addHandler(CMD* cmd,CmdHandler handler){ 20 //添加命令处理插槽 21 int num=cmd->mID-mHandlers.size()+1; 22 if(num>0){ 23 for(int i=0;i<num;i++) 24 mHandlers.push_back(vector<CmdHandler>()); 25 } 26 //增加命令 27 mHandlers[cmd->mID].push_back(handler); 28 } 29 30 //执行命令 31 static void execute(CMD* cmd){ 32 if(cmd->mID>mHandlers.size()) 33 return; 34 vector<CmdHandler>& handlers=mHandlers[cmd->mID]; 35 for(int i=0;i<handlers.size();i++) 36 handlers[i](cmd); 37 } 38 protected: 39 int mID;//每个类唯一
string mName;//方便调试
40 static int ID_GEN;//产生唯一连续id号 41 static vector<vector<CmdHandler>> mHandlers;//命令处理器 42 }; 43 44 //无参数 45 #define CMD_0(CMD_NAME)\ 46 class CMD_NAME : public CMD{\ 47 public:\ 48 CMD_NAME(){\ 49 static int ID=(++ID_GEN);\
mName=#CMD_NAME;\ 50 mID=ID;\ 51 }\ 52 };\ 53 //1个参数 54 #define CMD_1(CMD_NAME,PARAM1)\ 55 class CMD_NAME : public CMD{\ 56 public:\ 57 CMD_NAME(){\ 58 static int ID=(++ID_GEN);\
mName=#CMD_NAME;\ 59 mID=ID;\ 60 }\ 61 public:\ 62 PARAM1;\ 63 };\ 64 //2个参数 65 #define CMD_2(CMD_NAME,PARAM1,PARAM2)\ 66 class CMD_NAME : public CMD{\ 67 public:\ 68 CMD_NAME(){\ 69 static int ID=(++ID_GEN);\
mName=#CMD_NAME;\ 70 mID=ID;\ 71 }\ 72 public:\ 73 PARAM1;\ 74 PARAM2;\ 75 };\ 76 77 //定义命令 78 CMD_0(CMD_CLOSE); 79 CMD_0(CMD_RENDER); 80 CMD_1(CMD_PICK,vector<int> mResults);
#include "Cmd.h" int CMD::ID_GEN=-1; vector<vector<CmdHandler>> CMD::mHandlers; class SceneEditor{ public: SceneEditor(){ } void doPick(){ CMD_PICK cmd; cmd.mResults.push_back(5); cmd.mResults.push_back(100); CMD::execute(&cmd); } }; class MaterialEditor{ public: MaterialEditor(){ CMD_PICK cmd; CMD::addHandler(&cmd,CMD_HANDLER(MaterialEditor,onPick)); } protected: void onPick(CMD* cmd){ CMD_PICK* pick=(CMD_PICK*)cmd; vector<int>& results=pick->mResults; for(int i=0;i<results.size();i++) cout<<"MaterialEditor handle pick:"<<results[i]<<endl; } }; int main(int argc,char** argv){ SceneEditor* se=new SceneEditor(); MaterialEditor* me=new MaterialEditor(); se->doPick(); return 0; }
发这文章前慎重考虑了一下:如此没技术含量的东西该不该记录下来。
还是写一下吧,虽然它跟回调函数,监听者模式之类的没本质区别,但在实际项目中确实有效。
这是为了应对一个无处不在的问题:一处改变,几处做出反应。
这里之所以叫命令而不是消息,是因为它是立即执行的,会阻塞主线程。
添加命令处理器:
CMD_PICK cmd;
CMD::addHandler(&cmd,CMD_HANDLER(MaterialEditor,onPick));
发送命令:
CMD_PICK cmd; cmd.mResults.push_back(5); cmd.mResults.push_back(100); CMD::execute(&cmd);
定义命令,传入类名与参数:
CMD_0(CMD_CLOSE); CMD_0(CMD_RENDER); CMD_1(CMD_PICK,vector<int> mResults);
需要特别注意的是通过static变量为每个类生成唯一id,id就是数组下标,可直接定位到命令处理器。
麻烦的是循环发送命令,只能警告程序员尽量不要在命令处理器中发送命令。
最麻烦的是这些命令处理器何时失效。
相比这两大麻烦,我更受不了c++的类成员函数指针或者为一个函数写一个类称之为接口然后去继承。
所以还是用到了项目中,当然实际的会比这跟复杂健壮一些。
以后再慢慢改善。
 
                    
                     
                    
                 
                    
                 
                
            
         
 
         浙公网安备 33010602011771号
浙公网安备 33010602011771号