2015年6月21日日曜日

1-18. Memento パターン

カプセル化を維持したまま、あとでその状態に戻せるようにオブジェクトの内部状態を保存して
外面化します。



originator に操作を行っている途中で内部状態を保存したい場合、originator.createMemento()
によって memento を要求し、caretaker.addMemento() で保存します。内部状態は Memento
によってカプセル化されているので、Originator のカプセル化は維持されています。
保存した時点の状態に戻したい場合は、caretaker.getMemento() で保存した memento を取得し、
originator.setMemento() で内部状態を復帰します。
void client() {
	Caretaker caretaker = new Caretaker();
	Originator originator = new Originator();
	originator.operation("aaa");
	originator.operation("bbb");
	System.out.println("// 内部状態要求、保存");
	caretaker.addMemento(originator.createMemento()); // 0
	originator.operation("ccc");
	System.out.println("// 内部状態要求、保存");
	caretaker.addMemento(originator.createMemento()); // 1
	originator.operation("ddd");
	originator.operation("eee");
	System.out.println(originator.result());
	System.out.println("// 内部状態取得、復帰");
	originator.setMemento(caretaker.getMemento(1));
	System.out.println(originator.result());
}
class Originator {
	private String state;
	public Memento createMemento() {
		Memento memento = new Memento();
		memento.setState(this.state);
		return memento;
	}
	public void setMemento(Memento memento) { this.state = memento.getState(); }
	public void operation(String state) { this.state = state; }
	public String result() { return this.state; }
}
class Memento {
	private String state;
	public void setState(String state) { this.state = state; }
	public String getState() { return this.state; }
}
class Caretaker {
	private LinkedList<Memento> mementos = new LinkedList<>();
	public void addMemento(Memento memento) { this.mementos.add(memento); }
	public Memento getMemento(int index) { return this.mementos.get(index); }
}
出力結果:
// 内部状態要求、保存
// 内部状態要求、保存
eee
// 内部状態取得、復帰
ccc

サンプルプログラムとして、簡易的なエディタを示します。
指定した状態に保存、復帰しています。
実行結果:
// 内部状態要求、保存
// 内部状態要求、保存
Hello World!!
// 内部状態取得、復帰
Hello World
package design_pattern;

import java.util.LinkedList;

/**
 * Memento パターン
 * GoF
 * 
 * カプセル化を維持したまま、あとでその状態に戻せるようにオブジェクトの内部状態を保存して
 * 外面化します。
 * 
 * @author 2015/05/30 matsushima
 */
public class MementoSample {

	/**
	 * main
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		new MementoSample().client();
	}
	
	/**
	 * client
	 */
	void client() {
		Editor_Caretaker caretaker = new Editor_Caretaker();
		Editor_Originator editor = new Editor_Originator();
		editor.input("Hello");
		editor.input(" ");
		System.out.println("// 内部状態要求、保存");
		caretaker.addMemento(editor.createMemento()); // 0
		editor.input("World");
		System.out.println("// 内部状態要求、保存");
		caretaker.addMemento(editor.createMemento()); // 1
		editor.input("!!");
		System.out.println(editor.getText());
		System.out.println("// 内部状態取得、復帰");
		editor.setMemento(caretaker.getMemento(1));
		System.out.println(editor.getText());
	}

	/** Originator: エディタ。 */
	class Editor_Originator {
		private StringBuilder text = new StringBuilder();
		public Editor_Memento createMemento() {
			Editor_Memento memento = new Editor_Memento();
			memento.setState(this.text.toString());
			return memento;
		}
		public void setMemento(Editor_Memento memento) {
			this.text.setLength(0);
			this.text.append(memento.getState());
		}
		public void input(String text) {
			this.text.append(text);
		}
		public String getText() {
			return this.text.toString();
		}
	}
	/** Memento: エディタの保存状態。 */
	class Editor_Memento {
		private String state;
		public void setState(String state) {
			this.state = state;
		}
		public String getState() {
			return this.state;
		}
	}
	/** Caretaker: エディタの管理人。 */
	class Editor_Caretaker {
		private LinkedList<Editor_Memento> mementos = new LinkedList<>();
		public void addMemento(Editor_Memento memento) {
			this.mementos.add(memento);
		}
		public Editor_Memento getMemento(int index) {
			return this.mementos.get(index);
		}
	}
}

0 件のコメント:

コメントを投稿