命令调度机制

 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++的类成员函数指针或者为一个函数写一个类称之为接口然后去继承。

所以还是用到了项目中,当然实际的会比这跟复杂健壮一些。

以后再慢慢改善。

posted on 2012-12-08 23:58  SoMiSoDo  阅读(328)  评论(0)    收藏  举报

导航