# 메멘토 (Memento) 패턴

# 메멘토 패턴은 무엇인가요?

TIP

메멘토 패턴은 객체의 상태 정보를 저장하고 사용자의 필요에 의하여 원하는 시점의 데이터를 복원 할 수 있는 패턴을 의미합니다.

즉, 캡슐화를 유지하면서 객체의 내부 상태를 외부에 저장하는 방법이다.

  • 우리가 인텔리제이를 사용할 때, ctrl+z를 누르면 뒤로가듯이!

image

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