5

コンソールからコマンドを読み取り、コマンドに応じていくつかのアクションの1つを実行するプログラムがあります。これが私がこれまでに持っているものです:

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);
}

コマンドが大量にある場合はswitch、ステートメントの代わりにinを使用すると少し役立ちます。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

コマンドの数が少なく、可能なパラメーターが実際に少ない場合は、switchcaseを使用し続けることができます。

コマンドの数が増える場合は、コマンドデザインパターンを検討してください(これは、IMHOのある種の戦略パターンを偽装したものです。コマンドパターンと戦略パターンの違いについては、戦略パターンとコマンドパターンの使用を参照してください)。

ほとんどのコマンドがすべて同じ動作の一部を共有している場合は、テンプレートメソッドパターンを忘れないでください。

コマンドオブジェクトの作成が複雑になる場合(つまり、コマンドラインの入力のデコード/理解が複雑になる場合)、インタープリターのデザインパターンを確認する必要があります。

インタープリターパターンを使用して設計しているときに、複雑さが発生する場合(インタープリターに多くの作業が必要な場合、構文の問題などが発生する場合)、おそらくDSL、ドメイン固有言語を調べて、あなた自身の入力に適合する(そしてあなた自身の入力にのみ適合する)独自の言語。

于 2012-11-12T12:33:14.980 に答える
-1

-はしごは大丈夫ですifelse

原則として、に置き換えることができmap<string, Function>ますが、この具体的なケースでは何も得られません(コマンドの数が多い場合でも、特定の利益がないために複雑さが増します)。

私が最初にこれを書いたとき、私はしかし言及するのを忘れました:

  • コマンドハンドラーを個別の関数にします。

そうしないと、if-elseラダーがかなり乱雑になる可能性があります...ソリューションには個別の関数が必要であるため、すべて-直接-ここ-ラダーmapよりも少しきれいに見える可能性があります。しかし、それは実際には別個の機能であり、明確さの尺度を提供しますが、少し損をします(マップを維持するための余分な作業と、対処するための余分なレベルの間接参照を追加します)。ifelsemap

一方、「コンソールからコマンドを読み取る」はインタラクティブな入力を示しているため、ユーザーが写真に写っているので、同じ入力行から2つ以上のコマンドを読み取る必要はありません。それはプロンプトを台無しにし、ユーザーにはかなり困惑しているように見える可能性があるためです。>>したがって、を使用して一度に入力の「単語」を読み取る代わりに、一度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 に答える