Memento パターン (データ構造に対するその個所個所の操作内容, 状態をしておき, 以前の状態の復帰, 操作の再実行を行えるようにする)

[Memento] = [形見, 記念].

このパターンは, あるオブジェクトの任意の時点の状態を覚えておき (保存), 後でその状態にオブジェクトを戻すための工夫を提供するパターン. (カプセル化を破壊せずに, 状態を元に戻せる)

つまり, テキストエディタ等で実装されているような [アンドウ] (操作をキャンセルして操作前の状態に戻す) 機能を提供するためのパターンである.

注意:

状態を元に戻すための必要最小限の情報 (フィールド値) のみを保存すると言うこと.

役割

  1. Originator (作成者):
自分の状態を保存した [Memento] を作成する. (createMemento) また, 要求された [Memento] に状態を戻す. (setMemento) 自身の状態を [Memento] として保持する, 与えられた [Memento] から自身の状態を復元するという役割を担う.
  1. Memento (形見, 記念品):
[Originator] の内部情報 (フィールド値) を保持する. [Memento] は [Originator] と親密な関係にある. (内部情報にアクセス)
  1. Caretaker (世話人):
[Originator] の状態を保存したい場合, ある時点に戻したい場合は, [Originator] に指示を出す. 保存するように指示を出した場合は, その時点の状態の [Memento] を受け取り, 保持する. (履歴の管理も可能) [Memento] を保持するタイミング,アンドウするタイミング [Memento] を保持するという役割を担う.

クラス図

Memento パターンのクラス図

_images/designpattern-memento011.gif

ソースコード

  1. Originator.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Originator{
    private int param1;
    private String param2;

    public Originator(int param1, String param2){
	this.param1 = param1;
	this.param2 = param2;
    }
    
    public void calcAdd(int addNum){
	param1 += addNum;
    }

    public void concat(String addStr){
	param2 = param2 + addStr;
    }

    public Memento createMemento(){
	return new Memento(param1, param2);
    }

    public void setMemento(Memento memento){
	this.param1 = memento.param1;
	this.param2 = memento.param2;
    }

    public String toString(){
	return "param1=>" + param1 + "/param2=>" + param2;
    }
}
  1. Memento.java
1
2
3
4
5
6
7
8
9
public class Memento{
    int param1;
    String param2;

    Memento(int param1, String param2){
	this.param1 = param1;
	this.param2 = param2;
    }
}
  1. Caretaker.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import java.util.Stack;

public class Caretaker{
    static Stack<Memento> mementoList = new Stack<Memento>();

    public static void main(String[] args){
	Originator originator = new Originator(0, "");
	for(int i = 0; i < 5; i++){
	    for(int j = i; j < i + 5; j++){
		originator.calcAdd(j);
		originator.concat(Integer.toString(j));
	    }
	    mementoList.push(originator.createMemento());
	}

	originator.calcAdd(5);
	originator.concat(Integer.toString(5));
	System.out.println(originator);

	while( mementoList.size()!=0 ){
	    Memento memento = (Memento)mementoList.pop();
	    originator.setMemento(memento);
	    System.out.println(originator);
	}
    }
}

上記のプログラムの実行結果:

[wtopia Memento]$ java Caretaker
param1=>105/param2=>01234123452345634567456785
param1=>100/param2=>0123412345234563456745678
param1=>70/param2=>01234123452345634567
param1=>45/param2=>012341234523456
param1=>25/param2=>0123412345
param1=>10/param2=>01234