Command パターン

「Command」という英単語は、「命令」を意味します。

このパターンでは、1つもしくは複数の命令を1つのオブジェクトで表現(命令の詳細処理をカプセル化)します。また、命令をオブジェクトとして管理するため、その命令の履歴管理、UNDO(取消し)機能の実装等が容易に行えます。


役割り

1. Command(命令)
命令のインタフェースを定義します。
2. ConcreteCommandA・B(具体的な命令)
「Command」のインタフェースを実装します。
3. Receiver(受信者)
「Command」の処理対象となるオブジェクトのインタフェースです。
4. ConcreteReceiver(具体的な受信者)
「Receiver」のインタフェースを実装します。 この様に、「Receiver」インタフェースを介することで、複数の命令の受取手(「ConcreteReceiver」)を 作成することができます。
5. Invoker(起動者)
「Command」で定義されているインタフェースを呼出します。 また、複数の「ConcreteCommand」を保持することにより、命令の履歴管理機能、UNDO機能等を提供します。
6. Client(利用者)
「ConcreteCommandA・B」の初期設定(「ConcreteReceiver」を命令の受取手としてセット)、それらの命令を格納 した「Invoker」の起動を行います。 「Command」パターンを適用したクラスを利用し処理します。

▲PageTop

クラス図

Commandパターンのクラス図

Commandパターン クラス図

▲PageTop

サンプル

ソースコード

1. Command.java

public abstract class Command {
    public void setReceiver(Receiver receiver) {}
    public abstract void execute();
}

2-1. ConcreteCommandA.java

public class ConcreteCommandA extends Command {
    private int id;
    protected Receiver receiver;
    private final String name = "A";
    public ConcreteCommandA(int id) {
        this.id = id;
    }
    public void setReceiver(Receiver receiver) {
        this.receiver = receiver;
    }
    public void execute() {
        receiver.action(name + ":" + id);
    }
}

2-2. ConcreteCommandB.java

public class ConcreteCommandB extends Command {
    private int id;
    protected Receiver receiver;
    private final String name = "B";
    public ConcreteCommandB(int id) {
        this.id = id;
    }
    public void setReceiver(Receiver receiver) {
        this.receiver = receiver;
    }
    public void execute() {
        receiver.action(name + ":" + id);
    }
}

3. Receiver.java

public interface Receiver {
    public abstract void action(String msg);
}

4. ConcreteReceiver.java

public class ConcreteReceiver implements Receiver {
    public void action(String msg) {
        System.out.println(msg);
    }
}

5. Invoker.java

import java.util.Iterator;
import java.util.Stack;

public class Invoker {
    private Stack<Command> commands = new Stack<Command>();
    public void addCommnad(Command command) {
        commands.push(command);
    }
    public void undoCommnad() {
        Command command = (Command) commands.pop();
        System.out.println();
        System.out.println("undo - 削除された命令 ↓");
        command.execute();
        System.out.println("undo - 削除された命令 ↑");
        System.out.println();
    }
    public void execute() {
        Iterator<Command> it = commands.iterator();
        while (it.hasNext()) {
            it.next().execute();
        }
    }
}

6. Client.java

public class Client {
    public static void main(String[] args) {
        Command[] commandsA = new Command[5];
        Command[] commandsB = new Command[5];
        Receiver receiver = new ConcreteReceiver();
        Invoker invoker = new Invoker();
        for (int i = 0; i < commandsA.length; i++) {
            commandsA[i] = new ConcreteCommandA(i);
            commandsA[i].setReceiver(receiver);
            invoker.addCommnad(commandsA[i]);
        }
        for (int i = 0; i < commandsB.length; i++) {
            commandsB[i] = new ConcreteCommandB(i);
            commandsB[i].setReceiver(receiver);
            invoker.addCommnad(commandsB[i]);
        }
        invoker.execute();
        invoker.undoCommnad();
        invoker.execute();
    }
}

実行結果

C:\sample\desin_pattern\Command>javac Client.java [Enter]

C:\sample\desin_pattern\Command>java Client [Enter]
A:0
A:1
A:2
A:3
A:4
B:0
B:1
B:2
B:3
B:4

undo - 削除された命令 ↓
B:4
undo - 削除された命令 ↑

A:0
A:1
A:2
A:3
A:4
B:0
B:1
B:2
B:3
        

▲PageTop