I tried to implement some implementation of Memento pattern in Java.
Example is easy - copy video game as example, when user press F5
save gamer state => after pressing F9
recover last saved gamer state.
Here is output from easy run:
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
But it is wrong result, because last 2 lines should be:
Health: 90
Killed Monsters: 2
I couldn't figure out what is wrong. Code looks ok.
Here is code snippet:
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();
}
}
Any suggestions?
The problem is that you are reusing the same
GameState
reference in theGameMemento
object. So when you change property of theGameState
object, it is also changing the one that were saved in theGameMemento
.To fix this is necessary to save a copy of the
GameState
object instead its original reference, change your code as the example below:You can also use the clone method to copy the current instance of the
GameState
.