본문 바로가기
필수 개발지식/디자인패턴

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

by 코딩하는짱구 2023. 5. 15.
반응형

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

✅행동패턴의 메멘토(Memento)에 대해 알아보자!


행동패턴(Behavioral Patterns)이란?

 

객체나 클래스 사이의 알고리즘이나 책임 분배에 관련된 패턴이다.
한 객체가 수행할 수 없는 작업을 여러 개의 객체로 어떻게 분배하며 객체 사이의 결합도 최소화에 중점을 둔다.
패턴을 주로 클래스에 적용하는지 아니면 객체에 적용하는지에 따라 구분되는 패턴이다.


메멘토(Memento)패턴이란?

메멘토패턴은 객체 내부의 상태를 외부에 저장을 하고 저장된 상태를 다시 복원하고자 할 때에 사용하는 패턴이다.

메멘토패턴을 사용함으로써 객체의 모든 정보를 외부로 노출시키지 않고 캡슐화를 지킬 수 있다.

 

 

 

메멘토 패턴은 세 가지 주요 구성 요소로 구성되는데,

 

  • Originator(원조자): 상태를 저장하고 복원해야 하는 객체, 상태를 저장하는 메서드와 복원하는 메서드를 가진다.
  • Memento(메멘토): 객체의 상태를 저장하는 역할, 원조자 객체에 의해 생성되고 상태를 저장하고 있는 객체.
  • CareTaker(관리자_client): 메멘토를 관리하는 객체, 원조자 객체의 상태를 저장하거나 복원하기 위해 메멘토 객체를 사용한다.

 

 

 

 

**캡슐화란?

서로 연관있는 속성과 기능들을 하나의 캡슐(capsule)로 만들어 데이터를 외부로부터 보호하는 것

우리가 아플 때 한 번씩 먹게 되는 캡슐 약을 떠올려보면, 우리는 캡슐 안에 어떤 색의 내용물이 있는지, 또 어떤 성분의 약이 들어있는지 알 수 없습니다. 또한, 그 안의 내용물은 캡슐을 통해서 외부로부터 오염되지 않고 안전하게 보호될 수 있습니다.

 

자바의 캡슐화도 이와 같다고 할 수 있습니다. 즉, 외부로부터 클래스에 정의된 속성과 기능들을 보호하고, 필요한부분만 외부로 노출될 수 있도록 하여 각 객체 고유의 독립성과 책임 영역을 안전하게 지키고자 하는 목적이 있습니다.

 

자바 객체 지향 프로그래밍에서 이렇게 캡슐화를 하는 이유로 크게 두 가지를 언급할 수 있습니다.

  • 데이터 보호(data protection) – 외부로부터 클래스에 정의된 속성과 기능들을 보호
  • 데이터 은닉(data hiding) – 내부의 동작을 감추고 외부에는 필요한 부분만 노출

 

✅메멘토(Memento)는 어떻게 쓰일까?

// Originator 클래스
//상태를 저장하고 복원해야 하는 객체, 상태를 저장하는 메서드와 복원하는 메서드를 가진다.
class Editor {
  constructor() {
    //초기값은 빈 문자열
    this.content = '';
  }

  //텍스트를 입력받아 content 변수에 추가한다
  type(text) {
    this.content += text;
  }

  //현재 content의 값을 반환한다
  getContent() {
    return this.content;
  }

  //현재 content의 상태를 저장하기위해 Memento 객체를 생성하여 반환한다
  createMemento() {
    return new Memento(this.content);
  }
 //주어진 Memento객체에서 상태를 가져와 content에 복원한다
  restoreFromMemento(memento) {
    this.content = memento.getState();
  }
}

// Memento 클래스
//객체의 상태를 저장하는 역할, 원조자 객체에 의해 생성되고 상태를 저장하고 있는 객체.
class Memento {
  constructor(content) {
    //editor 객체의 상태를 저장하고,
    this.state = content;
  }
  //상태를 반환한다.
  getState() {
    return this.state;
  }
}

// Caretaker 클래스
//메멘토를 관리하는 객체, 원조자 객체의 상태를 저장하거나 복원하기 위해 메멘토 객체를 사용한다.
class History {
  constructor() {
    this.states = [];
  }

  //코드를 실행하면 가장 최근에 저장된 상태인 Hello가 반환되는거긔
  push(state) {
    this.states.push(state);
  }

  pop() {
    return this.states.pop();
  }
}

// 예제 실행
const editor = new Editor();
const history = new History();

editor.type('Hello'); //type('text')에 Hello를 할당
history.push(editor.createMemento()); //createMemonto를 불러 현재 상태를 저장. 이 상태는 history객체의 states배열에 저장

editor.type(' World!');
console.log(editor.getContent()); // text World!를 추가하면 현재 editor 객체의 content는 'Hello world!'가 된다.

editor.restoreFromMemento(history.pop()); //가장 최근에 저장된 상태를 복원한다.
console.log(editor.getContent()); // 출력: Hello

결국 메멘토는 오리지네이터의 상태의 '스냅샷' 역할을 한다. 

여기선 'Hello'를 저장해놓고 world이전의 Hello를 반환해주는 것. 

코드가 실행되는 순서를 잘 인지해놓으면 이해가 쉽다.

 

요악하면 memento 클래스에 복원하고자 하는 객체의 상태가 저장되고, history에서 memento 객체들을 관리, 조작하는 것.

memento 와 history가 나뉘어져 있는 이유는, memento 클래스만이 원조자의 상태를 캡슐화하고, 원조자에 의해 생성되며, 원조자만이 memento 내부에 접속할 수 있기 때문이다. memento 객체는 원조자의 상태를 외부에서 수정할 수 없도록 보호한다. 주로 getState()와 같은 메서드를 통해 원조자의 상태를 반환한다. 

✅메멘토(Memento)의 장단점?

장점

  • 캡슐화를 위반하지 않고 객체의 상태의 스냅샷들을 생성할 수 있다.
  • 케어테이커가 오리지네이터의 상태의 기록을 유지하도록 하여 오리지네이터의 코드를 단순화할 수 있다.

단점

  • 클라이언트들이 메멘토들을 너무 자주 생성하면 앱이 많은 RAM을 소모할 수 있다.
  •  케어테이커들은 더 이상 쓸모없는 메멘토들을 파괴할 수 있도록 오리지네이터의 수명주기를 추적해야 한다.
  •  PHP, 파이썬 및 JavaScript와 같은 대부분의 동적 프로그래밍 언어에서는 메멘토 내의 상태가 그대로 유지된다고 보장할 수 없다.
반응형