• このエントリーをはてなブックマークに追加

スポンサードリンク

はじめに

前回の続き.

コマンドパターン (Command Pattern) と Visitor Pattern で なにが違うのかよくわからなかったので, 比較しつつ, Command Pattern を実装してみた.

Command Pattern とは

動作を表現するオブジェクト. 動作とそれに伴うパラメータをカプセル化したもの.

特徴

  • Command オブジェクトは, 手続きに必要なパラメータの一時格納場所として便利. 関数呼び出しのためのパラメータを集めて, 後で使用するためにコマンドを保存しておくことができる.
  • 関数呼び出しのためのパラメータを集めて, 後で使用するためにコマンドを保存しておくことができる. 保存されたデータ構造に対する追加, 削除が可能になる.
  • コマンドの生成と実行のタイミングの分離.

Visitor パターンとの比較

わかりやすいように, Command ということばをここでは Visitor とする.

Visitor Pattern

オブジェクトの関係

  • Receiver は たくさん.
  • Visitor は 単一.

データと操作の関係

  • データは Visitor, 操作は Receiver がもつ.
  • Receiver は Visitor によって異なる操作をする.

Command Pattern

オブジェクトの関係

  • Receiver は 単一.
  • Visitor は たくさん.

データと操作の関係

  • データと操作は Visitor がもつ.
  • Receiver は Visitor によって同じ操作を実施する.

Code

前回の Visitor のコードを少し残しつつ, コードを改良してみた.

Invoker というコマンドを貯めておくデータ構造を追加した.

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

class CommandSample {

	////////////////////
	// Data
	////////////////////
	abstract public static class Command {
    public void setReceiver (Receiver receiver){}
		public abstract void execute ();
		// abstract public void accept (Receiver printer);
	}
	
	public static class Data1 extends Command {
		protected Receiver receiver;

		private String str1 = "Suzuki";
		private String str2 = "Ichiro";

		// データは隠蔽 getter は提供しない
		// public String getStr1 () {
		// 	return "Suzuki";
		// }
		// public String getStr2 () {
		// 	return "Ichiro";
		// }

    public void setReceiver (Receiver receiver){
			this.receiver = receiver;
    }

    public void execute (){
			receiver.action (str1 + " " + str2);
    }		
		
		// public void accept (Receiver printer) {
		// 	printer.visit (this);
		// }
	}

	public static class Data2 extends Command {
		protected Receiver receiver;

		private String str = "Jonney";

		// データは隠蔽, getter は提供しない
		// public String getStr () {
		// 	return "Jonney";
		// }

    public void setReceiver (Receiver receiver){
			this.receiver = receiver;
    }

		// public void accept (Receiver printer) {
		// 	printer.visit (this);
		// }

    public void execute (){
			receiver.action (str);
    }		
	}

	public interface Receiver {
		// public void visit (Data1 data);
		// public void visit (Data2 data);
		public abstract void action (String msg);
	}
	
	public static class NamePrinter implements Receiver {
		// コマンドに応じて処理を変更しない.
		// public void visit (Data1 data) {
		// 	String str1 = data.getStr1 ();
		// 	String str2 = data.getStr2 ();
		// 	System.out.println (str1 + " " + str2);
		// }

		// public void visit (Data2 data) {
		// 	String str = data.getStr ();
		// 	System.out.println (str);			
		// }

    public void action (String msg){
			System.out.println (msg);
    }		
	}

	////////////////////
	// Invoker
	////////////////////
	public static class Invoker{
    private Stack<Command> commands = new Stack<Command>();

    public void addCommand (Command command){
			commands.push (command);
    }
		
    public void execute (){
			for ( Command command : commands ) {
				command.execute ();
			}
    }
	}
	
	public static void main (String[] args) {
		NamePrinter name = new NamePrinter ();		
		Command data1, data2;
		Invoker invoker = new Invoker ();

		data1 = new Data1 ();
		data1.setReceiver (name);
		data2 = new Data2 ();
		data2.setReceiver (name);

		invoker.addCommand (data1);
		invoker.addCommand (data2);
		
		invoker.execute ();
	}
}

操作のカプセル化

Wikipedia の説明をみると, クロージャー機能に似ている気がした.

というわけで, 内部 (匿名, 無名) クラスを利用してみる.

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

class CommandSample {

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

	public static interface Executer {
		public void run ();
	}
	
	public static class Data1 extends Command {
		protected Receiver receiver;

		private String str1 = "Suzuki";
		private String str2 = "Ichiro";

    public void setReceiver (Receiver receiver){
			this.receiver = receiver;
    }

    public void execute () {
			receiver.action (new Executer () {
					public void run () {
						System.out.println (str1 + " " + str2);
					}
				});
    }		
		
	}

	public static class Data2 extends Command {
		protected Receiver receiver;

		private String str = "Jonney";

    public void setReceiver (Receiver receiver){
			this.receiver = receiver;
    }

    public void execute () {
			receiver.action (new Executer () {
					public void run () {
						System.out.println (str);
					}
				});
    }		
	}		

	////////////////////
	// Receiver
	////////////////////
	public interface Receiver {
		public abstract void action (Executer executer);
	}
	
	public static class NamePrinter implements Receiver {
    public void action (Executer executer){
			executer.run ();
    }		
	}

	////////////////////
	// Invoker
	////////////////////
	public static class Invoker{
    private Stack<Command> commands = new Stack<Command>();

    public void addCommand (Command command){
			commands.push (command);
    }
		
    public void execute (){
			for ( Command command : commands ) {
				command.execute ();
			}
    }
	}
	
	public static void main (String[] args) {
		NamePrinter name = new NamePrinter ();		
		Command data1, data2;
		Invoker invoker = new Invoker ();

		data1 = new Data1 ();
		data1.setReceiver (name);
		data2 = new Data2 ();
		data2.setReceiver (name);

		invoker.addCommand (data1);
		invoker.addCommand (data2);
		
		invoker.execute ();
	}
}

こうみると, Visitor Pattern にまた似てきた. 混乱してきたので今日はここまで.

  • Command Pattern: call Command -> call Receiver -> call Executer
  • Visitor Pattern: call Receiver -> call Visitor