티스토리 뷰
되돌리기 기능인 undo를 생각해보자.
객체 지향의 프로그램에서 undo 기능을 실행하려면 인스턴스가 가지고 있는 정보를 저장해 둘 필요가 있다.
단, 저장만 해서는 쓸모가 없고 저장한 정보로부터 인스턴스를 원래의 상태로 되돌려야 한다.
인스턴스를 복원하려면 인스턴스 내부의 정보를 자유롭게 액세스할 수 있어야 한다.
하지만 원하지 않는 액세스를 허용하면 클래스 내부 구조에 의존한 코드가 프로그램의 여기저기로 흩어질 수 있어 클래스의 수정을 어렵게 한다.
메멘토 패턴을 사용하여 인스턴스의 상태를 나타내는 역할을 도입해서 캡슐화의 파괴에 빠지지 않고 저장과 복원을 실행할 수 있다.
memento는 ‘기념품', ‘유물', ‘추억거리' 라는 의미를 가진다.
어떤 시점의 인스턴스의 상태를 확실하게 기록해서 저장해 두면 나중에 인스턴스를 그 시점의 상태로 되돌릴 수 있다.
다음 링크는 메멘토 패턴의 예제 코드다.
간단히 설명하면 아래 예제 코드는 ‘과일을 모으는 주사위 게임’이다.
Gamer의 인스턴스를 생성하고, 그것을 사용해서 게임을 실행한다.
Gamer의 bet 메서드를 반복해서 호출하고 그때마다 소지금을 표시한다.
변수 memento에는 ‘어떤 시점의 Gamer의 상태'가 저장되어 있다.
운 좋게 소지금이 증가하면 createMemento를 사용해서 현재의 상태를 저장한다.
소지금이 부족하게 되면 restoreMemento 메서드에게 memento를 제공해서 소지금을 원복한다.
메멘토 패턴의 등장인물
Originator(작성자)의 역할 - Gamer
자신의 현재 상태를 저장하고 싶을 때 Memento 역할을 만든다.
또한, 이전의 Memento 역할을 전달받으면 그 Memento 역할을 만든 시점의 상태로 돌리는 처리를 실행한다.
Memento(기념품)의 역할 - Memento
Originator 역할의 내부 정보를 정리한다.
Originator 역할의 내부 정보를 가지고 있지만, 그 정보를 누구에게도 공개하지 않는다.
Memento 역할은 다음 두 종류의 인터페이스(API)를 가지고 있다.
wide interface(넓은 인터페이스)
- 오브젝트의 상태를 원래의 상태로 돌리기 위해 필요한 정보를 모두 얻을 수 있는 메서드의 집합
- Memnto 역할의 내부 상태를 들어내기 때문에 이것을 사용하는 것은 Originator 뿐이다.
narrow interface(좁은 인터페이스)
- 외부의 Caretaker 역할에게 보여준다.
- 좁은 인터페이스로 할수 있는 일에는 한계가 있고 내부 상태가 외부에 공개되는 것을 방지한다.
이 두 종류의 인터페이스(API)를 구별해서 사용하면 오브젝트의 캡슐화가 파괴되는 것을 막을 수 있다.
Caretaker(관리인)의 역할 - Main
현재의 Originator 역할의 상태를 저장하고 싶을 때, 그것을 Originator에게 전한다.
Originator는 그것을 받아서 Memento를 만들어 Caretaker에게 전달한다.
Caretaker은 미래의 필요에 대비해서 그 Memento를 저장해 둔다.
그러나 Caretaker은 Memento가 갖는 두 개의 인터페이스 중에서 좁은 인터페이스만 사용할 수 있으므로 Memento의 내부 정보에 엑세스할 수 없다.
단, 만들어준 Memento를 한 덩어리의 블랙박스로서 통째로 저장해 둘 뿐이다.
엑세스 제어
단지, public이면 넓은 인터페이스(API), 그렇지 않으면 좁은 인터페이스(API)의 개념이 아니다.
여기서 ‘좁다'는 ‘내부상태를 조작할 수 있는 정도가 적다’의 의미다.
즉, getter가 public이라고 넓은 인터페이스가 아니라는 의미다.
Memento의 개수와 유효기간
Memento의 인스턴스를 여러 개로 지정하면 여러 시점에서의 상태를 저장할 수 있다.
예제 코드처럼 메모리 상에서만 Memento를 저장한다면 문제될 건 없다.
하지만, 파일로서 지속적으로 저장할 경우에는 문제가 된다.
어느 시점의 Memento를 파일로 저장해 두더라도 그 후 프로그램이 버전 업되면 파일로서 저장되어 있는 Memento와 모순이 발생할 우려가 있다.
🤔
Caretaker와 Originator를 분리하는 이유가 뭘까?
Caretaker는 어느 시점에서 스냅샷을 찍을지 결정하고, 언제 undo할지를 결정하는 Memento를 저장한다.
Originator는 Memento를 만드는 일과 제공된 Memento를 사용해서 자신의 상태를 원래 상태로 돌리는 일을 수행한다.
두 역할은 앞에서와 같이 역할분담을 수행하고 있다.
- 여러 단계의 undo를 실행하도록 변경하고 싶다
- undo 기능뿐만이 아니라 현재의 상태를 파일에 저장하고 싶다
같은 수정사항이 와도 Originator를 변경할 필요가 없어진다.
관련 패턴
- Command 패턴
- Prototype 패턴
- State 패턴
'JAVA > 디자인 패턴' 카테고리의 다른 글
플라이웨이트(Flyweight) 패턴 (0) | 2022.04.18 |
---|---|
상태(State) 패턴 (0) | 2022.04.18 |
옵저버(Observer) 패턴 (0) | 2022.04.02 |
미디에이터(Mediator) 패턴 (0) | 2022.04.02 |
파사드(Facade) 패턴 (0) | 2022.03.31 |
- Total
- Today
- Yesterday
- AWS
- 클린 코드
- 알고리즘
- Java
- C++
- 백준
- JPA
- 클린 아키텍처
- programmers
- 이팩티브 자바
- BOJ
- Algorithm
- Kotlin
- node.js
- Effective Java
- 프로그래머스
- kotest
- Spring Boot
- BAEKJOON
- kkoon9
- Spring
- 테라폼
- 정규표현식
- Olympiad
- 디자인 패턴
- 이펙티브 자바
- 디자인패턴
- MSA
- 코테
- 객체지향
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |