도서 요약 / / 2023. 1. 15. 21:17

[JAVA 언어로 배우는 디자인 패턴 입문] Memento 패턴

'JAVA 언어로 배우는 디자인 패턴 입문'의 내용을 정리한 것입니다.

Memento 패턴

  • 텍스트 에디터를 사용할 때, 실행 취소(undo) 기능을 이용하면, 삭제 하기 전 상태로 텍스트를 복원할 수 있다.
  • 실행 취소를 구현하려면 인스턴스가 가진 정보를 저장해 두어야 한다.

예제 프로그램

  • 예제 프로그램은 '과일 모으기 주사위 게임'


Memento 클래스

public class Memento {

    private int money;

    private List<String> fruits;

    public int getMoney() {
        return money;
    }

    Memento(int money) {
        this.money = money;
        this.fruits = new ArrayList<>();
    }

    void addFruit(String fruit) {
        fruits.add(fruit);
    }

    List<String> getFruits() {
        return new ArrayList<>(fruits);
    }
}

Gamer 클래스

public class Gamer {

    private int money;

    private List<String> fruits = new ArrayList<>();

    private Random random = new Random();

    private static String[] fruitsName = {
            "사과", "포도", "바나나", "오렌지"
    };

    public Gamer(int money) {
        this.money = money;
    }

    public int getMoney() {
        return money;
    }

    public void bet() {
        int dice = random.nextInt(6) + 1;
        if (dice == 1) {
            money += 100;
            System.out.println("소지금이 증가했습니다.");
        } else if (dice == 2) {
            money /= 2;
            System.out.println("소지금이 절반으로 줄었습니다.");
        } else if (dice == 6) {
            String f = getFruits();
            System.out.println("과일(" + f + ")를 받았습니다.");
            fruits.add(f);
        } else {
            System.out.println("변동 사항이 없습니다.");
        }
    }

    public Memento createMemento() {
        Memento m = new Memento(money);
        for (String f: fruits) {
            if (f.startsWith("맛있는 ")) {
                m.addFruit(f);
            }
        }
        return m;
    }

    public void restoreMemento(Memento memento) {
        this.money = memento.getMoney();
        this.fruits = memento.getFruits();
    }

    @Override
    public String toString() {
        return "[money = " + money + ", fruits = " + fruits + "]";
    }

    private String getFruits() {
        String f = fruitsName[random.nextInt(fruitsName.length)];
        if (random.nextBoolean()) {
            return "맛있는 " + f;
        } else {
            return f;
        }
    }
}

Main 클래스

public class Main {

    public static void main(String[] args) {
        Gamer gamer = new Gamer(100);
        Memento memento = gamer.createMemento();

        for (int i=0; i<100; i++) {
            System.out.println("==== " + i);
            System.out.println("상태: " + gamer);

            gamer.bet();

            System.out.println("소지금은 " + gamer.getMoney() + "원이 되었습니다.");

            if (gamer.getMoney() > memento.getMoney()) {
                System.out.println("많이 늘었으니 현재 상태를 저장하자!");
            } else if (gamer.getMoney() < memento.getMoney() / 2) {
                System.out.println("많이 줄었으니 이전 상태를 복원하자");
                gamer.restoreMemento(memento);
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {}
            System.out.println();
        }
    }
}

실행 결과

==== 0
상태: [money = 100, fruits = []]
변동 사항이 없습니다.
소지금은 100원이 되었습니다.

==== 1
상태: [money = 100, fruits = []]
과일(맛있는 포도)를 받았습니다.
소지금은 100원이 되었습니다.

==== 2
상태: [money = 100, fruits = [맛있는 포도]]
변동 사항이 없습니다.
소지금은 100원이 되었습니다.

==== 3
상태: [money = 100, fruits = [맛있는 포도]]
변동 사항이 없습니다.
소지금은 100원이 되었습니다.

==== 4
상태: [money = 100, fruits = [맛있는 포도]]
소지금이 증가했습니다.
소지금은 200원이 되었습니다.
많이 늘었으니 현재 상태를 저장하자!

Originator(작성자) 역

  • 자신의 현재 상태를 저장하고 싶을 때 만든 시점의 상태로 되돌리는 처리를 한다.
  • Gamer 클래스가 이 역할

Memento(기념품) 역

  • Originator의 내부 정보를 정리

Caretaker(관리인) 역

  • 현재 Originator의 상태를 저장하고 싶을 때 Originator에 요청
  • Main 클래스가 Caretaker 역



반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유