[디자인패턴] 메멘토 패턴 (Memento Pattern)

koline·2023년 9월 8일
0

디자인패턴

목록 보기
19/24

메멘토 패턴


클래스 설계 관점에서 객체의 정보를 저장할 필요가 있을 때 적용하는 디자인 패턴으로 Undo 기능을 개발할 때 사용하는 패턴이다.



구조


  1. 오리지네이터(originator): 내부 상태를 보유하고 있는 일부 객체이다. 케어테이커는 오리지네이터에 대해 무언가를 하지만 변경에 대한 실행 취소를 하기를 원한다.
  2. 케어테이커(caretaker): 먼저 오리지네이터에게 메멘토 객체를 요청한다. 그 뒤 예정된 일련의 명령을 수행한다. 명령 이전의 상태로 되돌리기 위해 메멘토 객체를 오리지네이터에 반환한다.
  3. 메멘토(memento): 객체 자신은 불투명 자료형(케어테이커가 변경할 수 없거나 변경해서는 안 되는)이다.



구현


// Memento.java (Memento)
public class Memento {
    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }
}

// Originator.java (Originator)
public class Originator {
    private String state;

    public void setState(String state) {
        this.state = state;
    } 

    public String getState() {
        return state;
    }

    public Memento createMemento() {
        return new Memento(state);
    }

    public void restore(Memento memento) {
        state = memento.getState();
    }
}

// CareTaker.java (CareTaker)
public class CareTaker {
    List<Memento> stateList = new ArrayList<>();

    public void add(Memento state) {
        stateList.add(state);
    }

    public Memento get(int index) {
        return stateList.get(index);
    }
}

// Client.java (Client)
public class Client {
    public static void main(String[] args) {
        Originator originator = new Originator();
        CareTaker careTaker = new CareTaker();

        originator.setState("사고로 기억력에 장애가 생김.");
        originator.setState("부인을 죽임.");
        originator.setState("가상의 인물인 새미 잰킨스를 만들어 사고를 새미의 일로 기억함.");
        careTaker.add(originator.createMemento());
        System.out.println("current state : " + originator.getState());

        originator.setState("부인을 죽인 존G를 찾으러 다님.");
        careTaker.add(originator.createMemento());
        System.out.println("current state : " + originator.getState());

        originator.setState("테디(본명은 존 에드워드 갬멀)가 도와줘서 범인(기억력 잃게 된 사고의 범인) 죽임.");
        originator.restore(careTaker.get(1));
        System.out.println("current state : " + originator.getState());


        originator.setState("계속 범인 찾아 다니다가 지미(나탈리의 남친) 죽임.");
        originator.setState("나탈리에게 이용당해서 도드라는 사람 죽임.");
        originator.setState("대신 존G에 대한 힌트 얻음.");
        careTaker.add(originator.createMemento());
        System.out.println("current state : " + originator.getState());

        originator.setState("테드 너 이름이 존G 구나.");
        originator.setState("죽이려다가 테디가 사실대로 말해줌.");
        originator.setState("그래도 일단 죽임.");
        originator.restore(careTaker.get(1));
        System.out.println("current state : " + originator.getState());
    }
}

// 실행 결과
current state : 가상의 인물인 새미 잰킨스를 만들어 사고를 새미의 일로 기억함.
current state : 부인을 죽인 존G를 찾으러 다님.
current state : 부인을 죽인 존G를 찾으러 다님.
current state : 대신 존G에 대한 힌트 얻음.
current state : 부인을 죽인 존G를 찾으러 다님.

결국 주인공은 평생 존G를 찾아 죽이고 다니고 본인은 그 동안 죽인 진범을 포함한 수 많은 존G들과 그 외의 무고한 피해자들을 기억하지 못하고 복수하러 다닌다.

이 처럼 Memento 클래스는 상태를 가지고 있는 인스턴스로 클라이언트가 직접 생성하거나 변경할 수 없다. 클라이언트는 Originator 객체를 통해 상태를 등록하고 변경한다. 이 중에 저장할 상태는 createMemento 메소드를 통해 Memento 인스턴스로 만들고 CareTaker에 저장한다. 만약 특정 상태로 되돌리고 싶으면 CareTaker에 저장된 메멘토 객체를 가지고와 Originator의 restore 메소드로 상태를 저장한다.

정리하자면, 각각의 역할을 메멘토 영화에 비유하자면 다음과 같다.

Originator: 영화의 주인공 레너드. 계속해서 변하는 상태(기억)을 가지고 있으나 상태를 저장할 수는 없다. 저장(기억)하기 위해서는 문신을 새기거나 사진을 찍어 메모를 남겨둔다.
Memento: 저장되는 기억의 객체로, 영화로 치자면 문신이나 사진과 메모라고 할 수 있다.
CareTaker: 기억을 저장해두고 되돌릴 수 있는 어떤것. 영화로 치면 모호하지만, 사진을 저장해둔 주머니나 필름? 이라고 볼 수 있을 듯(문신은 undo할 수 없기 때문에,,)




장점

  1. 저장된 상태를 핵심 객체와는 다른 별도의 객체에 보관하기 때문에 안전하다
  2. 핵심 객체의 데이터를 계속해서 캡슐화된 상태로 유지할 수 있다
  3. 복구 기능을 구현하기 쉽다

단점

  1. 이전 상태의 객체를 저장하기 위한 Originator가 클 경우 많은 메모리가 필요하다
  2. 상태를 저장하고 복구하는 데 시간이 오래 걸리 수 있다
  3. 자바 시스템에서는 시스템의 상태를 저장할 때 직렬화를 사용하는 것이 좋다



참고


[디자인패턴] 디자인패턴이란? - 생성패턴, 구조패턴, 행위패턴

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

위키피디아 - 메멘토 패턴

나무위키 - 메멘토

profile
개발공부를해보자

0개의 댓글