LoginSignup
2
3

More than 5 years have passed since last update.

デザインパターン学習メモ:「Command」

Posted at

このパターンの目的

GoF本より引用する。

要求をオブジェクトとしてカプセル化することによって、異なる要求や、要求からなるキューやログにより、クライアントをパラメータ化する。また、取り消し可能なオペレーションをサポートする。

execute()のみをもつインタフェース(Java言語)を作成し、このインタフェースを実装したコマンド(命令)クラスを作る。
このコマンドクラスを要求として渡された処理の実行者は、その中身を知らなくてもexecute()を呼ぶことで実行することができる。つまり、処理の内部実装のカプセル化である。

さらに、カプセル化を用いて処理を抽象的に扱うことによって、共通の方法で要求の取り消しや再実行可能にする。
この場合は、状態の保存が必要になる。

実装例

『アジャイルソフトウェア開発の奥義』(P.203)をベースに作成。Commandパターンを利用したActive Objectパターンとして紹介されている。

Command.java
// Command役
public interface Command {
    public void execute();
}
ActiveObjectEngine.java
// Invoker役
public class ActiveObjectEngine {
    LinkedList<Command> itsCommands = new LinkedList<Command>();

    public void addCommand(Command c) {
        itsCommands.add(c);
    }

    // リストからコマンドを取り出し、一つずつ実行する
    public void run() {
        while(!itsCommands.isEmpty()) {
            Command c = itsCommands.getFirst();
            itsCommands.removeFirst();
            c.execute();
        }
    }
}
SimpleCommand.java
// ConcreteCommand役
public class SimpleCommand implements Command {
    private String name;

    public SimpleCommand(String name) {
        this.name = name;
    }

    @Override
    public void execute() {
        System.out.println("Executed by " + name);
    }
}
SleepCommand.java
// ConcreteCommand役
// 自身の処理が完了した後に、wakeUpCommandをEngineに登録する。
public class SleepCommand implements Command {
    private String name;
    private Command wakeUpCommand;
    private ActiveObjectEngine engine;
    private long sleepTimeMilliSec;
    private long startTime;
    private boolean started = false;

    public SleepCommand(String name, long sleepTimeMilliSec,
            ActiveObjectEngine engine, Command wakeUpCommand) {
        this.name = name;
        this.sleepTimeMilliSec = sleepTimeMilliSec;
        this.engine = engine;
        this.wakeUpCommand = wakeUpCommand;
    }

    @Override
    public void execute() {
        long currentTime = System.currentTimeMillis();
        if (!started) {
            System.out.println(name + " started.");
            started = true;
            startTime = currentTime;
            engine.addCommand(this);
        } else if ((currentTime - startTime) < sleepTimeMilliSec) {
            engine.addCommand(this);
        } else {
            System.out.println("Executed by " + name);
            engine.addCommand(wakeUpCommand);
        }
    }
}

実行例

java.Main.java
public class Main {
    public static void main(String[] args) {
        ActiveObjectEngine engine = new ActiveObjectEngine();
        engine.addCommand(new SimpleCommand("SimpleCommand-A"));
        engine.addCommand(new SimpleCommand("SimpleCommand-B"));
        engine.addCommand(new SleepCommand("SleepCommand-C", 3 * 1000, engine,
                new SimpleCommand("WakeupCommand-C")));
        engine.addCommand(new SimpleCommand("SimpleCommand-D"));

        engine.run();
    }
}
結果
Executed by SimpleCommand-A
Executed by SimpleCommand-B
SleepCommand-C started.
Executed by SimpleCommand-D
Executed by SleepCommand-C
Executed by WakeupCommand-C

基本的に順番通りに各Commandが実行されている。SleepCommandだけは、意図通りSleepしているため、完了が最後になっている。

参考文献

  • エリック ガンマ、ラルフ ジョンソン、リチャード ヘルム、ジョン プリシディース(1999)『オブジェクト指向における再利用のためのデザインパターン 改訂版』本位田 真一、吉田 和樹 監訳、SBクリエイティブ
  • ロバート・C・マーチン(2004)『アジャイルソフトウェア開発の奥義 第2版 オブジェクト指向開発の神髄と匠の技』瀬谷啓介訳、SBクリエイティブ
2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3