0

我尝试在 Java 中实现Memento 模式的一些实现。

示例很简单 - 以复制视频游戏为例,当用户按下F5保存玩家状态 => 按下F9恢复上次保存的玩家状态后。

这是轻松运行的输出:

Health:          100
Killed Monsters:   0
Health:           90
Killed Monsters:   2
Health:           81
Killed Monsters:   4
Health:           72
Killed Monsters:   6
Health:           64
Killed Monsters:   8
Health:           57
Killed Monsters:  10

但这是错误的结果,因为最后两行应该是:

Health:           90
Killed Monsters:   2

我无法弄清楚出了什么问题。代码看起来不错。

这是代码片段:

import java.util.Stack;

class GameState {
    private int health;
    private int killedMonsters;

    public GameState(int health, int killedMonsters) {
        this.health = health;
        this.killedMonsters = killedMonsters;
    }

    public double getHealth() {
        return health;
    }

    public int getKilledMonsters() {
        return killedMonsters;
    }

    public void setHealth(int health) {
        this.health = health;
    }

    public void setKilledMonsters(int killedMonsters) {
        this.killedMonsters = killedMonsters;
    }

    @Override
    public String toString() {
        return  String.format("Health: %1$12d\nKilled Monsters: %2$3d", health, killedMonsters);
    }
}

class GameMemento {
    private GameState gameState;

    public GameMemento(GameState gameState) {
        this.gameState = gameState;
    }

    public GameState getGameState() {
        return gameState;
    }
}

class GameOriginator {
    private GameState gameState = new GameState(100, 0);

    public void play() {
        System.out.println(gameState.toString());
        gameState.setHealth((int)(gameState.getHealth() * 0.9));
        gameState.setKilledMonsters(gameState.getKilledMonsters() + 2);
    }

    public GameMemento saveGame() {
        return new GameMemento(gameState);
    }

    public void loadGame(GameMemento memento) {
        gameState = memento.getGameState();
    }
}

class Caretacker {
    private GameOriginator game = new GameOriginator();
    private Stack<GameMemento> quickSaves = new Stack<>();

    public void shutThisDumbAss() {
        game.play();
    }

    public void F5() {
        quickSaves.push(game.saveGame());
    }

    public void F9() {
        game.loadGame(quickSaves.peek());
    }
}

public class MementoDemo {
    public static void main(String[] args) {
        Caretacker caretacker = new Caretacker();
        caretacker.F5();
        caretacker.shutThisDumbAss();
        caretacker.F5();
        caretacker.shutThisDumbAss();
        caretacker.shutThisDumbAss();
        caretacker.shutThisDumbAss();
        caretacker.shutThisDumbAss();
        caretacker.F9();
        caretacker.shutThisDumbAss();
    }
}

有什么建议么?

4

2 回答 2

1

您的堆栈引用了相同的 GameOriginator 对象。您将防御性副本保存在堆栈中以供以后检索。

public GameMemento saveGame() {
 return new GameMemento(new GameState(gameState.getHealth(), gameState.getKilledMonsters()));
}
于 2014-12-15T13:02:47.373 回答
1

问题是您GameState在对象中重用相同的引用GameMemento。因此,当您更改对象的属性GameState,它也会更改保存在GameMemento.

要解决此问题,需要保存GameState对象的副本而不是其原始引用,更改您的代码,如下例所示:

public GameMemento saveGame() {
     return new GameMemento(new GameState(gameState.getHealth(), gameState.getKilledMonsters()));
}

您还可以使用clone方法复制GameState.

于 2014-12-15T13:02:28.097 回答