# 메멘토 (Memento) 패턴
# 메멘토 패턴은 무엇인가요?
TIP
메멘토 패턴은 객체의 상태 정보를 저장하고 사용자의 필요에 의하여 원하는 시점의 데이터를 복원 할 수 있는 패턴을 의미합니다.
즉, 캡슐화를 유지하면서 객체의 내부 상태를 외부에 저장하는 방법이다.
- 우리가 인텔리제이를 사용할 때, ctrl+z를 누르면 뒤로가듯이!
originator : 원래 저장하고자 하는 데이터. 따라서 originator의 상태를 저장해야 한다.
careTaker : originator의 내부 상태 정보를 가져와서 저장하며, 이게 위에서 말하는 외부이다.
memento : 내부 상태 정보를 위한 클래스. careTaker는 originator의 상세한 정보를 직접 가지는 것이 아니라 memento 타입으로 참조한다.
- memento는 불변 객체로 구현해야 한다.
# 메멘토 패턴은 언제 적용해야할까?
게임을 할 때, 세이브 포인트로 돌아가고 싶은 상황.
@Getter
@Setter
public class Game {
private int stage;
private int score;
}
public class Client {
public static void main(String[] args) {
Game game = new Game();
game.setStage(10);
game.setScore(20);
int score = game.getScore();
int stage = game.getStage();
Game restoredGame = new Game();
restoredGame.setScore(score);
restoredGame.setStage(stage);
}
}
- 클라이언트에서 Game의 필드 정보를 일일이 저장하고 있다.
- 이는 내부의 지식이 외부로 새어나가는 상황이며, 내부 정보의 의존성을 끊어 Game의 정보변경에 따른 클라이언트의 변경 가능성을 없애야 한다.
# 메멘토 패턴의 적용 예시
- 클라이언트를 CareTaker라고 가정하고 코드를 작성하였다.
@Getter
@Setter
public class Game {
private int stage;
private int score;
public GameSave save() {
return new GameSave(this.stage, this.score);
}
public void restore(GameSave gameSave) {
this.stage = gameSave.getStage();
this.score = gameSave.getScore();
}
}
@Getter
public final class GameSave {
private final int stage;
private final int score;
public GameSave(int stage, int score) {
this.stage = stage;
this.score = score;
}
}
public class Client {
public static void main(String[] args) {
Game game = new Game();
game.setStage(20);
game.setScore(10);
GameSave save = game.save();
game.setStage(22);
game.setScore(12);
game.restore(save);
System.out.println(game.getScore());
System.out.println(game.getStage());
}
}
# 메멘토 패턴의 장점과 단점
장점
- 저장된 상태를 핵심 객체와는 다른 별도의 객체에 보관하기 때문에 안전하다
- 캡슐화를 지키면서 상태 객체 상태 스냅샷을 만들 수 있다.
- 객체 상태 저장하고 또는 복원하는 역할을 CareTaker에게 위임할 수 있다.
- 객체 상태가 바뀌어도 클라이언트 코드는 변경되지 않는다.
단점
- 이전 상태의 객체를 저장하기 위한 Mementor가 많아지거나 크기가 클 경우 메모리 사용량에 영향을 줄 수 있다
- 상태를 저장하고 복구하는 데 시간이 오래 걸리 수 있다.
- 자바 시스템에서는 시스템의 상태를 저장할 때 직렬화를 사용하는 것이 바람직하다.
# 메멘토 패턴의 실 사용 예시
- 객체의 직렬화
import java.io.Serializable;
@Getter
@Setter
public class Game implements Serializable {
private int stage;
private int score;
}
import java.io.*;
public class MementoInJava {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// TODO Serializable
Game game = new Game();
game.setStage(10);
game.setScore(20);
// TODO 직렬화
try(FileOutputStream fileOut = new FileOutputStream("saveFile.hex");
ObjectOutputStream out = new ObjectOutputStream(fileOut))
{
out.writeObject(game);
}
game.setStage(15);
game.setScore(25);
// TODO 역직렬화
try(FileInputStream fileIn = new FileInputStream("saveFile.hex");
ObjectInputStream in = new ObjectInputStream(fileIn))
{
game = (Game) in.readObject();
System.out.println(game.getStage());
System.out.println(game.getScore());
}
}
}
# 출처
- https://lktprogrammer.tistory.com/65
- https://kingchan223.tistory.com/317?category=894627
- https://velog.io/@cham/Design-Pattern-%EB%A9%94%EB%A9%98%ED%86%A0-%ED%8C%A8%ED%84%B4-Memento-Pattern