You will be fine

<디자인패턴입문> 15. Memento 패턴

by BFine
반응형

 

www.yes24.com/Product/Goods/2918928

 

Java 언어로 배우는 디자인 패턴 입문

이 책은 디자인 패턴의 입문서입니다. GoF가 정리한 23개의 디자인 패턴을 하나씩 다루면서 객체 지향을 잘 모르는 초보자도 이해하기 쉽도록 정리하고 있습니다. 단순한 이론이나 논리을 제시하

www.yes24.com

 

가. 무엇인가

 a. 추억... 

  -  Memento는 기억이라는 의미를 가지고 있다. Memento(메멘토) 패턴도 이 기억이라는 키워드에 대한 패턴이다. 

  -  워드나 한글 같은 텍스트 에디터를 사용할때 실수로 작성 중인 글을 지워도 실행취소(Ctrl+Z)로 복원할 수 있다.

  -  객체지향에서 undo를 만들려면 인스턴스가 가지고 있던 정보를 저장할 필요가 있다.

      => 필요할때 이 저장된 기억으로 되돌리는 것이 필요하다.

  -  복원하기 위해서는 인스턴스 내부 정보를 자유롭게 액세스 할 수 있어야한다.

  -  하지만 원치않은 액세스를 허용하면 내부 구조에 의존한 코드가 여기저기 흩어져 수정을 어렵게 만들 수 있다.

      => 이를 캡슐화의 파괴라고 한다.

 

 b. 상태를 기억 

  -  Memento(메멘토) 패턴은 인스턴스의 상태를 나타내는 역할를 도입해 저장과 복원을 실행하는 패턴이다.

 

나. 만들어본 예제

save 시점의 Inventory의 내용을 기억해서 복원하는 예제

 a. Originator(작성자)의 역할

  -  Originator의 역할은 자신의 현재 상태를 저장하고 싶을때 Memento 역할을 만들어서 저장한다. 

  -  그리고 복원할경우 이전기억인 Memento의 정보를 가져와서 해당시점의 상태로 돌리는 역할을 한다.

  -  또한 Memento를 설정하는 부분은 다른패키지에서 접근하지 못하도록 캡슐화한다. 

 b. Memento(기억)의 역할

  -  Memento 역할은 Originator 역할의 시점 상태를 가지고 있으며 다른 클래스에  정보를 공개하지 않는다.

  -  Originator 안에 private class 형태로 추가가 되어 외부에서는 존재를 모르도록 캡슐화한다. 

package memento.game;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class GameInventoryOriginator {

    private List<String> inventory;
    private Stack<Memento> mementoStack;

    public GameInventoryOriginator() {
        this.inventory = new ArrayList<>();
        this.mementoStack = new Stack<>();
    }

    public void obtainItem(String item){
        inventory.add(item);
    }

    public void printInventory(){
        System.out.println(String.join(", ",inventory));
    }

    void saveGame(){
        mementoStack.push(new Memento(new ArrayList<>(inventory)));
    }

    void loadGame(){
        Memento memento = mementoStack.pop();
        inventory = memento.getInventory();
    }

    private class Memento {

        private final List<String> inventory;

        Memento(List<String> inventory) {
            this.inventory = inventory;
        }

        List<String> getInventory() {
            return inventory;
        }
    }
}

 c. Caretaker(관리인)의 역할

  -  Originator의 현재 상태를 저장하고 싶을때 Originator에게 전달하여 Originator가 정보를 저장하도록 한다.

  -  또한 이전데이터로 복원하고 싶은 경우에도 전달하여 복원하도록 한다.

package memento.game;

public class Caretaker {

    public void save(GameInventoryOriginator gameInventory){
        gameInventory.saveGame();
    }

    public void load(GameInventoryOriginator gameInventory){
        gameInventory.loadGame();
    }

}

 d. Main

  -  Originator의 데이터를 복원하고 싶은 경우 패키지가 다르기 때문에 Caretaker를 통해서만 실행가능하다. 

package memento;

import memento.game.Caretaker;
import memento.game.GameInventoryOriginator;

public class Main {
    public static void main(String[] args) {
        Caretaker caretaker = new Caretaker();
        GameInventoryOriginator game = new GameInventoryOriginator();
        
        game.obtainItem("포션");
        game.obtainItem("화살");
        game.obtainItem("5성지팡이");
        game.printInventory();
        caretaker.save(game);

        game.obtainItem("양손검");
        game.obtainItem("불길한상자");
        game.printInventory();
        caretaker.load(game);

        game.printInventory();

    }
}
/**

"C:\Program Files\Java\jdk1.8.0_251\bin\java.exe" 
포션, 화살, 5성지팡이
포션, 화살, 5성지팡이, 양손검, 불길한상자
포션, 화살, 5성지팡이

*/

다. 정리

 a. Caretaker 역할과 Originator 역할을 분리하는 이유

  -  Caretaker는 어느 시점에 스냅샷을 찍을지, 언제 복원할지를 결정하는 역할을 한다. 

  -  Originator는 기억(Memento)를 생성과 자신의 상태 복원을 하는 역할을 한다. 

  -  이렇게 역할분담을 수행하고 있기 때문에 만약 '복원할때 로그를 DB에 남기고 싶은 경우'

      Originator 역할을 변경할 필요가 전혀없다. 

Memento 패턴은 어떤 객체의 상태를 기록하여 원하는 시점에 복원할 수 있도록 하는 패턴이다.
반응형

블로그의 정보

57개월 BackEnd

BFine

활동하기