デザインパターンを覚えたい (Memento)

Mementoパターン

状態の履歴を保存するパターン。対象のインスタンスの情報を保持するMementoクラスを作成する。
ポイントは

  • 保存・復元を行うクラスのインスタンス状態を保持するクラスを用意することで、内部状態操作を閉じた範囲で行える

こと。インスタンスを復元には内部状態にアクセスする必要があるけど、不用意にpublicにするとカプセル化の意味がなくなってします。
Mementoパターンではこのような内部操作を限定された範囲で行うようにできるとかなんとか。

実装。コンソール迷路探索ゲーム。
http://dl.dropbox.com/u/7810000/code/design_pattern/memento.zip

実行。今回はコンソール入力がカラムので起動はコマンド経由で。

$ ./run.sh
--- 中略 ---
##############################
#S ###### ###################
# ######## ###################
# ##### ## ###################
# ###################
####### ## ###################
####### ## ## ################
###### ## #############
################ #############
################ #############
####### #############
####### ##### ################
####### ##### ################
#### ## ################
#### #########################
#### #########################
#### #########################
#### #########################
#### ##### ## ################
### ##### #############
#### ##### ## ## #############
#### ## ## ##### #############
### ##### #############
#### ##### ##### #############
################ #############
############### #######
################ ##### #######
###################### #######
###################### @ ###
##############################

--- possible command ---
map : show map
l : go left
r : go right
save : save current state
load : load saved state
exit : end game

input>

レイアウトが崩れまくりんぐ/(^o^)\ナンテコッタイ。とりあえずsaveとload機能があるのがポイント。
ちなみに、迷路の生成方法は、下記サイトのクラスタリングによる方法を使ってます。
http://apollon.issp.u-tokyo.ac.jp/~watanabe/tips/maze.html

実装では迷路本体であるMazeクラスのなかでMementoの作成、復元を行なっている。

public class Maze {

    public void saveMemento() {
        memento = new Memento(xSize, ySize);

        memento.setCurX(curX);
        memento.setCurY(curY);

        for (int y=1; y<=ySize; y++) {
            for (int x=1; x<=xSize; x++) {
                memento.setVisit(x, y, map[y][x].getVisit());
            }
        }
    }

    public boolean restoreMemento() {
        if (memento == null) return false;

        curX = memento.getCurX();
        curY = memento.getCurY();

        for (int y=1; y<=ySize; y++) {
            for (int x=1; x<=xSize; x++) {
                map[y][x].setVisit(memento.getVisit(x, y));
            }
        }

        return true;
    }

}

Mementoクラスは以下のとおり。wide intearfaceとnarrow interfaceは全然意識してないので、実装としてはいまいちだと思う。

public class Memento {
    private int curX, curY;
    private boolean visitMap[][];

    protected Memento(int xSize, int ySize) {
        this.curX = -1;
        this.curY = -1;

        visitMap = new boolean[ySize+2][xSize+2];
    }

    protected void setCurX(int curX) {
        this.curX = curX;
    }

    public int getCurX() {
        return curX;
    }

    protected void setCurY(int curY) {
        this.curY = curY;
    }

    public int getCurY() {
        return curY;
    }

    protected void setVisit(int x, int y, boolean visit) {
        visitMap[y][x] = visit;
    }

    public boolean getVisit(int x, int y) {
        return visitMap[y][x];
    }
}

実装の中で、コンソールのクラスがすごく汚くなってるけど、これはCommandパターンをやるときにでも整理するかも。