본문 바로가기

Develop/Design Pattern

[Design Pattern] 메멘토 (Memento) 패턴

728x90

1. 개요

  • 메멘토 디자인 패턴 (Memento Design Pattern)객체의 상태를 기억해 두고 후에 객체를 불러올 수 있도록 하는 패턴이다.

2. 상황

  • 상태를 되돌리고자 할 때
  • 게임에서 체크포인트를 구현해야 할 때
  • 복잡한 작업을 취소 및 재실행해야 할 때

3. 다이어그램

memento-default

3.1. 설명

  • Originator
    • 상태를 저장하고 복원할 객체이다.
    • 이 객체는 현재 상태를 나타내는 정보를 가지고 있다.
  • Memento
    • Originator 객체의 상태를 저장하는 객체이다.
    • Originator의 내부 상태를 나타내는 정보를 가지고 있다.
  • Caretaker
    • Memento 객체를 관리하고 저장한다.
    • Originator의 상태를 복원하기 위해 필요한 Memento 객체를 보관한다.

4. 구현

public class Originator {
  private String attr;

  public Originator(String attr) { this.attr = attr; }
  void setAttr(String attr) { this.attr = attr; }
  void visualize() { System.out.println("attr: " + attr); }

  static class Memento {
    private final String attr;
    private Memento(String attr) { this.attr = attr; }
  }

  Memento create() { return new Memento(attr); }
  void restore(Memento m) { attr = m.getAttr(); }
}
public class Caretaker {
  private Originator.Memento m;

  public void set(Originator.Memento memento) { m = memento; }
  public Originator.Memento get() { return m; }
}
public class Client {
  public static void main(String[] args) {
    Originator o = new Originator("first");
    o.visualize();

    Caretaker caretaker = new Caretaker();
    caretaker.set(o.create());

    o.setAttr("second");
    o.visualize();

    o.restore(caretaker.get());
    o.visualize();
  }
}

출력결과

attr: first
attr: second
attr: first

5. 예시

import java.util.Stack;

public class TextEditor {
  private StringBuilder text = new StringBuilder();
  private Stack<Memento> undoStack = new Stack<>();
  private Stack<Memento> redoStack = new Stack<>();

  public void appendText(String newText) {
    undoStack.push(save());
    text.append(newText);
    redoStack.clear();
  }

  public void undo() {
    if (undoStack.isEmpty()) return;
    redoStack.push(save());
    Memento memento = undoStack.pop();
    restore(memento);
  }

  public void redo() {
    if (redoStack.isEmpty()) return;
    undoStack.push(save());
    Memento memento = redoStack.pop();
    restore(memento);
  }

  public void displayText() {
    System.out.println("Text: " + text.toString());
  }

  private Memento save() {
    return new Memento(text.toString());
  }

  private void restore(Memento memento) {
    text = new StringBuilder(memento.getText());
  }

  private static class Memento {
    private final String text;

    public Memento(String text) { this.text = text; }
    public String getText() { return text; }
  }
}
public class Client {
  public static void main(String[] args) {
    TextEditor editor = new TextEditor();

    editor.appendText("Hello, ");
    editor.appendText("World!");

    editor.displayText();

    editor.undo();
    editor.displayText();

    editor.redo();
    editor.displayText();
  }
}

출력결과

Text: Hello, World!
Text: Hello, 
Text: Hello, World!

6. 장단점

6.1. 장점

  • 객체의 캡슐화정보 은닉을 강화시킨다.
  • 상태 복원 코드의 유지보수가 쉽다.

6.2. 단점

  • 메모리 사용량이 증가한다.
  • 성능을 저하시킬 수 있다.

관련 포스팅

728x90