본문 바로가기
개발/디자인 패턴

[Java 언어로 배우는 디자인 패턴 입문] 상태를 관리하기 18. Memento

by hongdor 2021. 1. 15.
728x90

출처 : 책 - java 언어로 배우는 디자인 패턴 입문

 

18. Memento - 상태를 저장하기

 

 

1. 목적

 

 - 말 그대로 현재 상태를 저장하는 구조이다.

 - 유의해서 볼 점은 상태를 저장한 클래스의 메소드에 public이 없다는 점이다.(예제에서는 1개만 있음) 

   은닉하기 위함.

 - 의의 : 저장한 상태를 따로 분리함으로써, 저장한 상태를 파일로 만드는 작업등을 추가로 할 때

   오리지날 클래스는 건드리지 않도록 유지할 수 있다.

 

 

2. 예제

 

(1) Memento - 상태 저장. getMoney 메소드만 public 선언이 되어있다. (정보 은닉) 

                         같은 패키지인 Gamer 클래스에서만 Memento 메소드를 사용할 수 있고, Main에서는 호출할 수 없다.

package game;
import java.util.*;

public class Memento {
    int money;                           // 소지금
    ArrayList fruits;                       // 과일
    public int getMoney() {                // 소지금을 얻는다(narrow interface)
        return money;
    }
    Memento(int money) {                // 생성자(wide interface)
        this.money = money;
        this.fruits = new ArrayList();
    }
    void addFruit(String fruit) {            // 과일을 추가한다(wide interface)
        fruits.add(fruit);
    }
    List getFruits() {                      // 과일을 얻는다(wide interface)
         return (List)fruits.clone();
    }
}

 

 

(2) Gamer - Memento를 사용하는 역할.  createMemento(), restoreMemento(Memento memento)

package game;
import java.util.*;

public class Gamer {
    private int money;                             // 소지금
    private List 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) {                            // 1 - 소지금이 증가한다
            money += 100;
            System.out.println("소지금이 증가했습니다.");
        } else if (dice == 2) {                     // 2 - 소지금이 절반이 된다
            money /= 2;
            System.out.println("소지금이 절반이 되었습니다.");
        } else if (dice == 6) {                     // 6 - 과일을 받는다
            String f = getFruit();
            System.out.println("과일(" + f + ")을 받았습니다.");
            fruits.add(f);
        } else {                                    // 그외 - 변한 것이 없다
            System.out.println("변한 것이 없습니다.");
        }
    }
    public Memento createMemento() {                // 스냅샷을 찍는다
        Memento m = new Memento(money);
        Iterator it = fruits.iterator();
        while (it.hasNext()) {
            String f = (String)it.next();
            if (f.startsWith("맛있는 ")) {         // 과일은 맛있는 것만 보존
                m.addFruit(f);
            }
        }
        return m;
    }
    public void restoreMemento(Memento memento) {   // undo 실행
        this.money = memento.money;
        this.fruits = memento.getFruits();
    }
    public String toString() {                      // 문자열 표현
        return "[money = " + money + ", fruits = " + fruits + "]";
    }
    private String getFruit() {                     // 과일을 1개 얻는다
        String prefix = "";
        if (random.nextBoolean()) {
            prefix = "맛있는 ";
        }
        return prefix + fruitsname[random.nextInt(fruitsname.length)];
    }
}

 

 

(3) Main - Memento의 저장조건을 설정해준다.

import game.Memento;
import game.Gamer;

public class Main {
    public static void main(String[] args) {
        Gamer gamer = new Gamer(100);               // 최초의 소지금은 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() + "원이 되었습니다.");

            // Memento의 취급 결정
            if (gamer.getMoney() > memento.getMoney()) {
                System.out.println("    (많이 증가했으므로 현재의 상태를 저장하자)");
                memento = gamer.createMemento();
            } else if (gamer.getMoney() < memento.getMoney() / 2) {
                System.out.println("    (많이 감소했으므로 이전의 상태로 복원하자)");
                gamer.restoreMemento(memento);
            }

            // 시간 기다림
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            System.out.println("");
        }
    }
}

 

728x90

댓글