Command with Story(ストーリを持つコマンド)

Ver 1.0 - 1999/5/6

初版 1999,3/23
(株) 永和システムマネジメント
平鍋 健児
Kenji HIRANABE

 


目的

GUI をもつアプリケーションにおいて,ユーザとの対話によって 情報を集め,必要な情報がすべて集まった段階で実際の動作を行なう ようなコマンドを表現する.

別名

シナリオ(Scenario),インストーラ(Installer), ウィザード(Wizard)

動機

ワープロ,表計算,ドローツールのような GUI アプリケーションでは, 通常の動作はユーザ主導である.ユーザがその場その場で選択したメニュー や,ダブルクリックした画面上の要素によって,アプリケーションの動作が 決定される.ユーザのアクションはほとんど制約されていない.

別のパターンとして,インストールプログラム(インストーラ)を考える. インストーラの多くは一連のダイアログ(対話画面)によって構成され, 各ダイアログにおいてユーザがとることができるアクションは限られている. 各ダイアログの入力が終わると,ユーザは「次」を指定して次のダイアログに 進むか,または「戻る」を指定して前のダイアログに戻ることができる. 一連のダイアログでの入力が終わり,インストールに必要な情報がすべてそろうと アプリケーションはユーザに「確認」を求め,インストールの実行となる.
「〜ウィザード」と通常呼ばれるコマンドでも,システムが提供する道筋 (対話的なストーリ)に従ってユーザの入力が集められ,最終的に1つのコマンド が実行される.このように,アプリケーションがユーザを導くストーリを 持っているコマンドを「ストーリを持つコマンド」と呼ぶことにする.

ストーリを持つコマンドでは,制御を一旦アプリケーションで掌握する必要がある ため,対話は「モーダル」で行なわれ,ユーザのアクションを制約することが多い. GoF の Command パターンを使用してアプリケーションを構築し,1つの Command の execute メソッドでこのようなモーダルな対話を実現した場合, excute メソッドの中が繁雑になることが多い.また,各ダイアログを複数の Command として分割し,「次」の指定で別のコマンドを起動していく様な実装 では,ユーザの入力データが複数のコマンドにばらまかれ,その授受のための 仕組みが必要となる.

このパターンでは,Command パターンを拡張する.1つのコマンドの execute メソッド終了時に,Invoker に対して次のエントリーポイントを 返却する.Invoker は貰ったエントリーポイントを再度引数に与えて execute メソッドを呼び出す.Command が execute をすべて終えたら, 次のエントリーポイントとして END を返すことで,ストーリを持つコマンド の終了とする.

適用可能性

構造

構造
structure

構成要素

協調関係

 

協調関係
collaboration

 

実装

実装に置いては,以下の点を考慮する必要がある.

バリエーション

以下のようなバリエーションが考えられる.

結果

 

サンプルコード

java の inner class による実装

 

class command {
    public static void main(String v[]) {
        Invoker inv = new Invoker();
        inv.invoke(new InstallCommand());
    }
}
class Invoker {
  public void invoke(Command c) {
    Command next = c;
    while (next != null) {
      System.out.println(next);
      next = next.execute();
    }
  }
}

interface Command {
  public Command execute();
}

class InstallCommand implements Command {
  Hashtable regInfo;   // 登録情報
  String comp[];       // インストールコンポーネント
  String destDir;      // インストール先ディレクトリ

  // 全体のエントリポイント
  public Command execute() {
       // 最初のサブコマンド
       return new RegInfo();
  }

  // 登録情報収集サブコマンド
  private class RegInfo implements Command {
    public Command execute() {
       // regInfo を収集
      regInfo = new Hashtable();
      regInfo.put("name", "hiranabe");
       return new Comp(); // 次のエントリポイント
    }
  }

  // コンポーネント収集サブコマンド
  private class Comp implements Command {
    public Command execute() {
       // comp[] を収集
        comp = new String[] { "compA", "compB", "compC" };
       return new DestDir();
    }
  }

  // インストール先ディレクトリ収集サブコマンド
  private class DestDir implements Command {
    public Command execute() {
       // destDir を収集
       destDir = "/home/hiranabe";
       boolean ok = true;
       if (ok) 
          return new Go();  // インストール実行
       else
          return new RegInfo();  // 最初に戻る
    }
  }

  // インストールの実行
  private class Go implements Command {
    public Command execute() {
       // 実際の実行
       // ここで regInfo, comp[], destDir を
       // 参照することができる.
       System.out.println("regInfo = " + regInfo);
       System.out.println("comp[] = " + comp);
       System.out.println("destDir = " + destDir);
                          
       return null;
    }
  }
  
}

使用例

関連するパターン


mailto:hiranabe@esm.co.jp
Last modified: Sat May 1 15:07:16 1999