메멘토 패턴

이정석·2023년 6월 23일
0

디자인패턴

목록 보기
17/23

메멘토 패턴이란?

객체의 내부 사항을 공개하지 않으면서 이전 상태를 저장하고 복원할 수 있게 해주는 패턴


문제상황

1. level과 health를 가지고 있는 Game 클래스가 있다.

class Game {
    public String level;
    public int health;

    public Game(String level, int health) {
        this.level = level;
        this.health = health;
    }

    public void play(String level, int health) {
        this.level = level;
        this.health = health;
    }

    public String getLevel() {
        return level;
    }

    public int getHealth() {
        return health;
    }
}

Game은 현재 상태를 저장하고 각 변수의 getter가 있다.

2. Game의 상태를 복원하는 undo를 구현하기 위한 Client는 다음과 같다.

public class Client {
    public static void main(String[] args) {
        Game game = new Game("Level 1", 100);
        
        String savedLevel = game.getLevel();
        int savedHealth = game.getHealth();

        game.play("Level 2", 80);
        game.play(savedLevel, savedHealth);
    }
}

Game의 상태를 복원하기 위해 Client는 Game의 내부 상태를 직접 확인해 저장한다. 그 후 복원할 시점에 해당한 상태를 set함으로 예전 상태를 복원한다.

  • 위 상황은 Game 상태를 저장 및 복원하기 위해 Game의 필드 값을 직접 변경하는데, 이러한 접근 방식은 객체의 캡슐화를 깨트리고 Game의 내부 구조가 변경되면 Client의 코드도 수정해야 한다.

    상태만 저장하는 객체와 이 객체를 생성, 조회가 가능한 다른 객체를 통해 저장 및 복원 기능을 구현하자


구조

  1. Originator: 상태를 저장하고 복원할 수 있는 객체로 현재 상태를 가진다.
  2. Memento: Originator 객체의 상태정보를 저장하는 객체로 Originator만 Memento 객체를 생성하고 접근할 수 있다.
  3. Caretaker: Memento를 보관하는 클래스로 Originator에게 어떤 Memento의 상태로 복원할 것을 명령한다. Memento를 직접 생성 또는 조작하지 않는다.

코드(JAVA)

1. Game

class Game {
    private String level;
    private int health;

    public Game(String level, int health) {
        this.level = level;
        this.health = health;
    }

    public void play(String level, int health) {
        this.level = level;
        this.health = health;
    }

    public GameState save() {
        return new GameState(level, health);
    }

    public void restore(GameState state) {
        level = state.getLevel();
        health = state.getHealth();
    }
}

2. GameState


class GameState {
    private final String level;
    private final int health;

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

    public String getLevel() {
        return level;
    }

    public int getHealth() {
        return health;
    }
}

3. Client

public class Main {
    public static void main(String[] args) {
        Game game = new Game("Level 1", 100);

        GameState savedState = game.save();
        
        game.play("Level 2", 80);
        game.restore(savedState);
    }
}

문제 상황에서 savedLevelsavedHealth와 같은 내부 상태가 GameState 클래스로 나타낼 수 있고 상태 저장 및 복원은 Game에게 GameState를 전달함으로 동작한다.


Memento의 접근 제한 방법

Mement의 생성과 조작은 Originator만 할 수 있다고 설명했지만 위 코드는 GameState의 생성과 내부 데이터 조회가 가능하다.

public 생성자와 public getter이기 때문!

이를 구현하기 위해서 JAVA에는 nested class가, C++에는 friend class를 사용하면 된다.

  • nested class
public class Game {
    private String level;
    private int health;

    public void play(String level, int health) {
        this.level = level;
        this.health = health;
    }

    public GameState save() {
        return new GameState(level, health);
    }

    public void restore(GameState state) {
        level = state.level;
        health = state.health;
    }

    public class GameState {
        private final String level;
        private final int health;

        private GameState(String level, int health) {
            this.level = level;
            this.health = health;
        }
    }
}
  • friend class
class Game {
  private:
      string level;
      int health;

  public:
      void play(string level, int health);
      GameState* save();
      void restore(GameState* state);
};

class GameState {
  friend class Game;

  private:
      GameState(string level, int health) : level(level), health(health){}

      string level;
      int health;
};
profile
게임 개발자가 되고 싶은 한 소?년

0개의 댓글