5

我有一个程序应该从控制台读取命令,并根据命令执行几个操作之一。这是我到目前为止所拥有的:

void ConwayView::listening_commands() {
    string command;

    do {
        cin >> command;

        if ("tick" == command)
        {
            // to do
        }
        else if ("start" == command)
        {
            // to do for start
        }
        ...

    } while (EXIT != command);
}

如果有大量命令,使用 aswitch代替语句会有所帮助。if您建议使用哪些模式来提供交互式命令行?

4

6 回答 6

6

有多种方法可以解决这个问题,“正确”的解决方案是什么值得商榷。如果我要为自己的工作解决它,我会创建一个自定义结构的表。就像是:

struct CommandStruct {
    char *command;
    int (*commandHandler)(/*params*/);
} commandTable[] = {
    { "tick",  tickCommand },
    { "start", startCommand },
    ...
};

然后我的处理循环将遍历该表的每个元素,寻找正确的匹配项,例如:

for (int i = 0; i < TABLE_SIZE; ++i) {
    if (command == commandTable[i].command) { /* using whatever proper comparison is, of course */
        commandTable[i].commandHandler(/*params*/);
        break;
    }
}
于 2012-11-12T12:32:22.670 回答
5

不是真正的模式,但通常是一个好方法:

#include <map>
#include <functional>
#include <string>
#include <iostream>

typedef std::map< std::string, std::function<void(void)> > command_dict;
//                                           ^^^^^^^^
//                               the signature of your commands. probably should have an error code.

void command1() { std::cout << "commanda" << std::endl; }
void command2() { std::cout << "commandb" << std::endl; }
void command3() { std::cout << "commandc" << std::endl; }

int main() {
  command_dict c;
  c["a"] = &command1;
  c["b"] = &command2;
  c["c"] = &command3;

  std::string input;
  while(std::getline(std::cin, input)) { // quit the program with ctrl-d
    auto it = c.find(input);
    if(it != end(c)) {
      (it->second)(); // execute the command
    } else {
      std::cout << "command \"" << input << "\" not known" << std::endl;
    }
  }
}
于 2012-11-12T12:32:29.490 回答
4

如果命令数量很少并且可能的参数很少,您可以继续使用 switch case !

如果命令的数量增加,请考虑命令设计模式(恕我直言,这是某种伪装的策略模式:cf Using a strategy pattern and a command pattern for the difference between command and strategy patterns)。

如果您的大多数命令都共享相同行为的一部分,请不要忘记模板方法模式

如果创建命令对象的复杂性增加(即解码/理解命令行输入的复杂性),您应该开始查看解释器设计模式

如果在使用解释器模式进行设计时,您碰巧看到了一些复杂性(如果解释器需要太多工作,您会看到语法问题等等),那么您可能应该看看DSL,领域特定语言,并设计您的适合(并且仅适合)您自己的输入的自己的语言。

于 2012-11-12T12:33:14.980 回答
-1

-梯子很好ifelse

原则上它可以用 a 代替map<string, Function>,但是对于这个具体的情况,这不会给你带来任何好处(它增加了复杂性,没有特别的好处,即使有大量的命令)。

当我最初写这篇文章时,我忘了提及:

  • 使您的命令处理程序分离功能。

如果你不这样做,那么if-else梯子可能会变得非常混乱......该map解决方案需要单独的功能,因此看起来比一切都直接在这里if-else梯子更干净一些。但实际上是单独的函数提供了一定程度的清晰度,而这map会降低一点(在维护地图方面增加了额外的工作,以及额外的间接级别来应对)。

另一方面,由于“从控制台读取命令”表示交互式输入,因此图片中有用户,您不希望从同一行输入中读取两个或多个命令。因为这会搞砸提示,并且对用户来说似乎很莫名其妙。>>因此,不要使用一次读取输入的“单词”,而是std::getline一次读取整行输入。

于 2012-11-12T12:31:50.947 回答
-3

使用新的和改进的方式随意执行一堆命令:

int happy_time = 5;
int a = happy_time;
int muddy_dirt = 1;
int b = muddy_dirt;
int c = happy_time * muddy_dirt //really messy stuff

这可能是最简单的方法......

于 2014-03-17T03:56:15.533 回答
-6

如果您的命令很大,则必须使用类似数据库的访问。

于 2012-11-12T13:29:37.077 回答