プログラムがコンソールからコマンドを取得する場合、コマンドが有効であることを確認して実行するための標準/ベストプラクティスは何ですか?
のようなことを考えていましたHashMap<String,Object>
が、これはすべての文字列比較でパフォーマンスを低下させませんか?
3 に答える
まず第一に、パフォーマンスについて心配する必要はありません。そのための時間は後で来るでしょう(または、おそらく、まったく来ないでしょう)。コマンドの解析は、コマンドの実行よりも時間がかかりませんね。
コマンドの処理に関しては、まず、入力をアトミックトークンに分割する必要があります。これらは、コマンド自体、スイッチ-a -b -c、またはパラメーター値である可能性があり、「」の間にある場合もあります。
入力をトークンに分割したら、コマンドが存在するかどうかを確認します。含まれている場合は、トークンの供給がコマンドに対して有効かどうかを確認します。
どんなアーキテクチャを使いたいのかわかりません。1つのコマンドに1つのクラスを使用する場合もあれば、1つのクラスと多数のメソッドがある場合もあれば、非常に長いケースの1つのメソッドがある場合もあります。どちらがあなたに最適ですか?おそらく最後のものではありませんが、選択するものはすべて、コマンドとそのジョブの複雑さに一致する必要があります。
例1:
abstract class Command {
public abstract String getName();
public abstract int execute(String[] parameters); // not implemented in Cmd* below
}
class Cmd1 extends Command {
public String getName()
{
return "Cmd1";
}
}
class Cmd2 extends Command {
public String getName()
{
return "Cmd2";
}
}
//somewhere else:
public void execute(String[] params) {
Command[] commands = {new Cmd1(), new Cmd2()};
for (Command cmd: commands) {
if (cmd.getName().equals(params[0]) {
cmd.execute(params);
return;
}
}
throw new RuntimeException("unknown command "+params[0]);
}
例2:
void processCmd1(String[] params);
void processCmd2(String[] params);
public static final String CMD1 = "cmd1";
public static final String CMD2 = "cmd2";
static HashSet<String> availableCommands = new HashSet<String>();
static {
availableCommands.put(CMD1);
availableCommands.put(CMD2);
}
{
if (availableCommands.contains(params[0])) {
switch(params[0]) { // java 7
case CMD1:
processCmd1(params[0]);
break;
case CMD2:
processCmd2(params[0]);
break;
}
} else {
throw new RuntimeException("unknown command "+params[0]);
}
}
例3:
abstract class Command {
public abstract String getName();
public abstract int execute(String[] parameters); // not implemented in Cmd* below
}
class Cmd1 extends Command {
public String getName()
{
return "Cmd1";
}
}
class Cmd2 extends Command {
public String getName()
{
return "Cmd2";
}
}
static HashMap<String,Command> commandMap = new HashMap<String,Command>();
static {
Command cmd = new Cmd1();
commandMap.put(cmd.getName(), cmd);
cmd = new Cmd2();
commandMap.put(cmd.getName(), cmd);
}
//somewhere else:
public void execute(String[] params) {
Command cmd = commandMap.get(params[0]);
if (cmd == null) {
throw new RuntimeException("unknown command "+params[0]);
} else {
cmd.execute(params);
}
}
コマンドライン引数を処理するための優れたライブラリがあります。ApacheコモンズCLIです。
このための標準的なデザイン パターンは、責任の連鎖またはインタープリターですが、インタープリターはやり過ぎかもしれません。責任の連鎖は基本的に、if/then/else ステートメントとしてハードコーディングするのではなく、if/then/else 決定ツリーを動的に作成する方法です。
入力を前処理してから、Chain of Responsibility を使用して入力を解析します。
コマンド ラインの parg 処理用の標準ライブラリは、実行中のコードにコンパイルされる正式な文法を使用していると確信しています。少なくとも、私が最後に使った石器時代にはそうしていました (lex と yacc が一般的な選択肢でした) が、今日ではおそらくかなり専門化されています。