寻找最优雅的代码调度程序

时间:2009-08-19 16:19:46

标签: c++ c design-patterns coding-style

我认为问题很常见。您有一些输入字符串,并且必须根据字符串的内容调用函数。类似于字符串的switch()。 想一想命令行选项。

目前我正在使用:

using std::string;

void Myclass::dispatch(string cmd, string args) {
    if (cmd == "foo")
        cmd_foo(args);
    else if (cmd == "bar")
        cmd_bar(args);
    else if ...
        ...
    else
       cmd_default(args);
}

void Myclass::cmd_foo(string args) {
...
}

void Myclass::cmd_bar(string args) {
...
}

并在标题

class Myclass {
    void cmd_bar(string args);
    void cmd_foo(string args);
}

所以每个foo和bar我都要重复四次(4次)。我知道我可以先将函数指针和字符串提供给静态数组,然后在循环中进行调度,保存一些if ... else行。但是有一些宏技巧(或预处理器滥用,取决于POV),这使得有可能以某种方式定义函数,同时让它自动更新数组? 所以我只需要写两次,如果内联使用,可能只写一次?

我正在寻找C或C ++的解决方案。

5 个答案:

答案 0 :(得分:8)

听起来你正在寻找Command pattern

这样的事情:

像这样创建一个地图

std::map<std::string, Command*> myMap;

然后只需使用你的密钥执行这样的命令....

std::map<std::string, Command*>::iterator it = myMap.find(str);
if( it != myMap.end() ) {
    it->second->execute()
}

要注册命令,您只需执行此操作

myMap["foo"] = new CommandFoo("someArgument");
myMap["bar"] = new CommandBar("anotherArgument");

答案 1 :(得分:5)

根据问题评论中的链接,基本解决方案是将字符串映射到某种函数调用。

实际注册字符串 - &gt;函数指针/仿函数对:

首先,有一个单例(shock!horror!)调度程序对象。 我们称之为TheDispatcher - 它是map<string,Func>的包装器,其中 Func是你的函数指针或函子类型。

然后,有一个注册类:

struct Register {
   Register( comst string & s, Func f ) {
      TheDispatcher.Add( s, f );
   }
};

现在在您创建的各个编辑单元中 静态物体(震惊!恐怖!):

Register r1_( "hello", DoSayHello );

将创建这些对象(假设代码不在静态库中)并自动向TheDispatcher注册。

在运行时,您在TheDispatcher中查找字符串并执行相关的函数/函子。

答案 2 :(得分:2)

as alternative to the Command pattern您可以构建字符串哈希表 - &gt; 函数指针

typedef void (*cmd)(string);

答案 3 :(得分:1)

丑陋的宏观解决方案,你有点要求。请注意,它不会自动注册,但会确保某些内容保持同步,如果只添加映射而不是源文件中的函数,也会导致编译错误。

Mappings.h:

// Note: no fileguard
// The first is  the text string of the command, 
// the second is the function to be called, 
// the third is the description.
UGLY_SUCKER( "foo", cmd_foo, "Utilize foo." );
UGLY_SUCKER( "bar", cmd_bar, "Turn on bar." );

Parser.h:

class Myclass {
...
protected:
    // The command functions
    #define UGLY_SUCKER( a, b, c ) void b( args )
    #include Mappings.h
    #undef UGLY_SUCKER
};

Parser.cpp:

void Myclass::dispatch(string cmd, string args) {
    if (cmd == "")
        // handle empty case
#define UGLY_SUCKER( a, b, c ) else if (cmd == a) b( args )
#include Mappings.h
#undef UGLY_SUCKER
    else
       cmd_default(args);
}

void Myclass::printOptions() {
#define UGLY_SUCKER( a, b, c ) std::cout << a << \t << c << std::endl
#include Mappings.h
#undef UGLY_SUCKER
}

void Myclass::cmd_foo(string args) {
...
}

答案 4 :(得分:1)

您必须至少定义函数并将它们添加到某个注册表中。 (如果它们是某些类的非内联成员函数,则还必须声明它们。)除了生成实际代码的某些特定于域的语言(如cjhuitt's macro hackery)之外,我看不到任何方法提到这些功能两(或三)次。