본문 바로가기
Design Pattern/행동 패턴(Behavioral Patterns)

메멘토(Memento) - 행동 패턴(Behavioral Patterns)

by 김 민 준 2024. 5. 25.

 

메멘토 패턴은 개체의 상태를 저장하고 나중에 복원할 수 있도록 하는 디자인 패턴이다. 상태를 외부에 저장하지 않고 개체 자체에서만 관리하면서 특정 시점의 상태로 되돌릴 수 있다. 주로 실행취소와 같은 기능을 구현할때 사용된다.

 

주요 개념 부터 살펴보자.

 

1. Originator : 상태를 겆장하고 복원할 개체이다. 현재 상태를 캡슐화하여 메멘토 개체를 생성하고, 메멘토 개체를 사용하여 상태를 복원한다.

2. Memento : Originator 개체의 상태를 저장하는 개체 이다. 상태 정보를 캡슐화하여 외부에 노출하지 않는다.

3. Caretaker : 메멘토 개체를 관리하며,메멘토 개체를 저장하고 필요할 때 Originator 개체의 상태를 복원한다.

 

텍스트 편집기에서 텍스트를 입력하고 실행 취소할 수 있는 기능을 구현한 소스코드를 살펴보자.

 

// Memento 클래스: Originator 객체의 상태를 저장
class Memento {
    private final String state;

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

    public String getState() {
        return state;
    }
}

 

// Originator 클래스: 상태를 저장하고 복원하는 객체
class TextEditor {
    private String state;

    public void setState(String state) {
        System.out.println("Setting state to: " + state);
        this.state = state;
    }

    public String getState() {
        return state;
    }

    public Memento saveStateToMemento() {
        System.out.println("Saving state to memento: " + state);
        return new Memento(state);
    }

    public void getStateFromMemento(Memento memento) {
        state = memento.getState();
        System.out.println("State restored from memento: " + state);
    }
}

 

import java.util.Stack;

// Caretaker 클래스: Memento 객체를 관리
class Caretaker {
    private Stack<Memento> mementoStack = new Stack<>();

    public void addMemento(Memento memento) {
        mementoStack.push(memento);
    }

    public Memento getMemento() {
        if (!mementoStack.isEmpty()) {
            return mementoStack.pop();
        }
        return null;
    }
}

 

// Client 클래스: TextEditor와 Caretaker 객체를 사용하여 상태를 저장하고 복원
public class MementoPatternDemo {
    public static void main(String[] args) {
        TextEditor textEditor = new TextEditor();
        Caretaker caretaker = new Caretaker();

        // 상태 설정 및 저장
        textEditor.setState("State #1");
        caretaker.addMemento(textEditor.saveStateToMemento());

        textEditor.setState("State #2");
        caretaker.addMemento(textEditor.saveStateToMemento());

        textEditor.setState("State #3");

        // 실행 취소
        textEditor.getStateFromMemento(caretaker.getMemento());
        textEditor.getStateFromMemento(caretaker.getMemento());
    }
}

 

// 출력

//Setting state to: State #1
//Saving state to memento: State #1
//Setting state to: State #2
//Saving state to memento: State #2
//Setting state to: State #3
//State restored from memento: State #2
//State restored from memento: State #1

 

생각해보면 개발을 하다보면 이런 기능을 만드는 일이 많다. 그런데 보통은 트랜잭션을 사용하곤하는데 메멘토 패턴은 애플리케이션 레벨에서 복잡한 개체의 상태를 관리하거나 변경할때 사용할 수 있다. DB레벨에서 제공되는 트랜잭션 ACID(Atomicity, Consistency, Isolation, Durability)속성을 보장하고 이를 통해서 진행하는 경우도 많다. 

예를 들어, 애플리케이션에서 특정 시점의 개체상태를 저장하고 필요시 복원하여 롤백과 유사한 기능을 구현하는데 이경우 메멘토 패턴은 개체상태를 캡슐화하여 안전하게 관리하는데 유용한것이다.

 

그렇다고 메멘토 패턴이 트랜잭션을 대체한다는것은 아니다. 메멘토 패턴은 개체 상태 관리를 위한 보조적인 패턴으로 사용되는것이다. 

 

그럼 Command 패턴도 비슷한것 같은데? 

커맨드 패턴은 작업(액션)을 캡슐화 하여 관라히는것이고 메멘토 패턴은 개체의 상태를 캡슐화하여 관리하는것이다.

 

예를 들어 커맨드패턴은 텍스트 편집기에서 텍스트 입력, 삭제 등의 작업을 취소하거나 재실행하는 기능을 구현할 수 있다.

메멘토 패턴은 특정 시점 상태를 저장하고 취소하여 해당 상태로 복원하는것이다. 

 

액션과 상태으로 구분하면 좋을것이다.