技術とか戦略とか

IT技術者が技術や戦略について書くブログです。

javaでのCommandパターン

Commandパターンとはデザインパターンの一種で、1つ1つのコマンド(命令)をそのままオブジェクトとして表現するパターンです。
コマンドをオブジェクトとして表現することで、コマンドの管理(追加・削除・実行)が可能になるというメリットがあります。
 
今回は、ファイルやフォルダを作成するコマンドを管理するサンプルコードを作成してみました。
Commandクラスが1つ1つのコマンドを表し、コマンドの管理はInvokerクラスで行い、コマンドの実際の処理はReceiverクラスで記述します。
 
【サンプルコード】
・Command.java
// コマンドの抽象クラス
public abstract class Command {

    protected String nameOfFileFolder;
    protected Receiver receiver;

    // コンストラクタ:生成するファイル名・フォルダ名をセット
    public Command(String nameOfFileFolder) {
        this.nameOfFileFolder = nameOfFileFolder;
    }

    // コマンドの受け手をセット
    public void setReceiver(Receiver receiver) {
        this.receiver = receiver;
    }

    // コマンドの受け手に処理を依頼
    public abstract void execute();

}
 
・ConcreteCommandForOperation.java
// 運用で使用するフォルダ・ファイル作成を指示するクラス
public class ConcreteCommandForOperation extends Command {

    public ConcreteCommandForOperation(String nameOfFileFolder) {
        super(nameOfFileFolder);
    }

    public void execute() {
        receiver.action
            ("C:\\pleiades\\workspace\\Hello\\conf\\" + nameOfFileFolder);
    }

}
 
・ConcreteCommandForTemporary.java
// 一時フォルダ・ファイル作成を指示するクラス
public class ConcreteCommandForTemporary extends Command {

    public ConcreteCommandForTemporary(String nameOfFileFolder) {
        super(nameOfFileFolder);
    }

    public void execute() {
        receiver.action
            ("C:\\tmp\\" + nameOfFileFolder);
    }

}
 
・Receiver.java
// コマンドの受け手の抽象クラス
public interface Receiver {

    // 処理実行
    public abstract void action(String path);

}
 
・ConcreteReceiverMkfil.java
import java.io.File;
import java.io.IOException;
// ファイル作成を行うReceiver
public class ConcreteReceiverMkfil implements Receiver {

    public void action(String path) {
        File file = new File(path + ".txt");
        try {
            if (file.createNewFile()){
            }else{
                System.out.println(path + "作成に失敗しました。");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
 
・ConcreteReceiverMkdir.java
import java.io.File;
// フォルダ作成を行うReceiver
public class ConcreteReceiverMkdir implements Receiver {

    public void action(String path) {
        File file = new File(path);
        if (file.mkdir()){
        }else{
            System.out.println(path + "作成に失敗しました。");
        }
    }

}
 
・Invoker.java
import java.util.Iterator;
import java.util.Stack;
// コマンドの追加・取消・実行を管理するクラス
public class Invoker {

    private Stack<Command> commandStack = new Stack<Command>();

    // コマンドを追加する
    public void addCommnad(Command command) {
        commandStack.push(command);
        System.out.println
            (commandStack.size() + "個目のコマンドを登録しました。");
    }

    // 直近のコマンドを削除する
    public void undoCommnad() {
        if(commandStack.empty()) {
            System.out.println("削除するコマンドがありません。");
        } else {
            commandStack.pop();
            System.out.println
                ( (commandStack.size()+1) + "個目のコマンドを削除しました。");
        }
    }

    // コマンドを順番に実行する
    public void execute() {
        System.out.println
            (commandStack.size() + "個のコマンドを実行します。");
        Iterator<Command> itetator = commandStack.iterator();
        while (itetator.hasNext()) {
            itetator.next().execute();
        }
        System.out.println("コマンドを実行しました。");
    }

}
 
・CommandMain.java
// メインクラス
public class CommandMain {

    public static void main(String[] args) {

        // 初期処理
        Receiver receiverMkfil = new ConcreteReceiverMkfil();
        Receiver receiverMkdir = new ConcreteReceiverMkdir();
        Invoker invoker = new Invoker();

        // コマンドの作成(5個)
        System.out.println("Aファイルを作成するコマンドを登録します。");
        Command commandA = new ConcreteCommandForOperation("A");
        commandA.setReceiver(receiverMkfil);
        invoker.addCommnad(commandA);
        System.out.println("Bフォルダを作成するコマンドを登録します。");
        Command commandB = new ConcreteCommandForOperation("B");
        commandB.setReceiver(receiverMkdir);
        invoker.addCommnad(commandB);
        System.out.println("C一時ファイルを作成するコマンドを登録します。");
        Command commandC = new ConcreteCommandForTemporary("C");
        commandC.setReceiver(receiverMkfil);
        invoker.addCommnad(commandC);
        System.out.println("D一時フォルダを作成するコマンドを登録します。");
        Command commandD = new ConcreteCommandForTemporary("D");
        commandD.setReceiver(receiverMkdir);
        invoker.addCommnad(commandD);
        System.out.println("Eファイルを作成するコマンドを登録します。");
        Command commandE = new ConcreteCommandForOperation("E");
        commandE.setReceiver(receiverMkfil);
        invoker.addCommnad(commandE);

        // 直近のコマンドの削除
        invoker.undoCommnad();

        // コマンドの実行
        invoker.execute();

    }

}
 
【実行結果】
・コンソール出力
Aファイルを作成するコマンドを登録します。
1個目のコマンドを登録しました。
Bフォルダを作成するコマンドを登録します。
2個目のコマンドを登録しました。
C一時ファイルを作成するコマンドを登録します。
3個目のコマンドを登録しました。
D一時フォルダを作成するコマンドを登録します。
4個目のコマンドを登録しました。
Eファイルを作成するコマンドを登録します。
5個目のコマンドを登録しました。
5個目のコマンドを削除しました。
4個のコマンドを実行します。
コマンドを実行しました。
 
・ファイルやフォルダの生成確認
C:\pleiades\workspace\Hello\conf>cd C:\pleiades\workspace\Hello\conf

C:\pleiades\workspace\Hello\conf>dir
 ドライブ C のボリューム ラベルは  です
 ボリューム シリアル番号は  です

 C:\pleiades\workspace\Hello\conf のディレクト

2020/02/08  10:02    <DIR>          .
2020/02/08  10:02    <DIR>          ..
2020/02/08  10:02                 0 A.txt
2020/02/08  10:02    <DIR>          B
               1 個のファイル                   0 バイト
               3 個のディレクトリ  19,379,642,368 バイトの空き領域

C:\pleiades\workspace\Hello\conf>
C:\pleiades\workspace\Hello\conf>cd C:\tmp\

C:\tmp>dir
 ドライブ C のボリューム ラベルは  です
 ボリューム シリアル番号は  です

 C:\tmp のディレクト

2020/02/08  10:02    <DIR>          .
2020/02/08  10:02    <DIR>          ..
2020/02/08  10:02                 0 C.txt
2020/02/08  10:02    <DIR>          D
               1 個のファイル                   0 バイト
               3 個のディレクトリ  19,379,642,368 バイトの空き領域

C:\tmp>