이 패턴의 고전적인 구현은 수많은 인기 프로그래밍 언어(예: C++, C# 및 자바)에서 사용할 수 있는 중첩 클래스에 대한 지원에 의존한다
이 구현에서 메멘토 클래스는 오리지네이터 내부에 중첩된다. 이것은 오리지네이터가 메멘토의 필드들과 메서드들이 비공개로 선언된 경우에도 접근할 수 있도록 한다. 반면에, 케어테이커는 메멘토의 필드들과 메서드들에 매우 제한된 접근 권한을 가지므로 메멘토들을 스택에 저장할 수는 있지만 그들의 상태를 변조할 수는 없다.
중첩 클래스들을 지원하지 않는 프로그래밍 언어(예: PHP)에 적합한 대안적 구현 방식이다.
중첩 클래스들이 없는 경우, 케어테이커들이 명시적으로 선언된 중개 인터페이스를 통해서만 메멘토와 작업할 수 있는 규칙을 만들어 메멘토의 필드들에 대한 접근을 제한할 수 있다. 이 인터페이스는 메멘토의 메타데이터와 관련된 메서드들만 선언한다.
반면에 오리지네이터들은 메멘토 객체와 직접 작업하여 메멘토 클래스에 선언된 필드들과 메서드들에 접근할 수 있다. 이 접근 방식의 단점은 메멘토의 모든 구성원을 공개(public)로 선언해야 한다는 것이다.
다른 클래스들이 오리지네이터의 상태를 메멘토를 통해 접근할 가능성을 완전히 제거하고자 할 때 유용하다.
이 구현 방식을 사용하면 여러 유형의 오리지네이터들과 메멘토들을 보유할 수 있다. 각 오리지네이터는 그에 상응하는 메멘토 클래스와 함께 작동한다. 오리지네이터들과 메멘토들은 자신의 상태를 누구에게도 노출하지 않는다.
케어테이커들은 이제 메멘토들에 저장된 상태의 변경에 명시적인 제한을 받는다. 또 케어테이커 클래스는 복원 메서드가 이제 메멘토 클래스에 정의되어 있으므로 오리지네이터에게서 독립된다.
각 메멘토는 그것을 생성한 오리지네이터와 연결된다. 오리지네이터는 자신의 상태 값들과 함께 자신을 메멘토의 생성자에 전달한다. 이러한 클래스 간의 긴밀한 관계 덕분에 메멘토는, 오리지네이터가 적절한 세터들을 정의했을 경우, 자신의 오리지네이터의 상태를 복원할 수 있다.
class Game {
var level: Int = 0
var score: Int = 0
func setLevel(level: Int) {
self.level = level
}
func setScore(score: Int) {
self.score = score
}
// Memento 생성 - Memento 생성자 주입으로 Originator 자체를 전달
func createMemento() -> SaveData {
print("Level : \(self.level), Score: \(self.score) 상태를 저장합니다.\n")
return SaveData(originator: self)
}
func printCurrentState() {
print("현재 상태 Level : \(self.level), Score: \(self.score)")
}
}
class SaveData {
private var originator: Game
private var level: Int = 0
private var score: Int = 0
// Memento 생성 시 Originator의 State를 전달받음 (이후 수정하지 않음)
init(originator: Game) {
self.originator = originator
self.level = originator.level
self.score = originator.score
}
// Originator의 State를 복원
func recover() {
self.originator.setLevel(level: self.level)
self.originator.setScore(score: self.score)
}
}
class GameDataSystem {
private var history: [SaveData] = []
func save(memento: SaveData) { // Memento 스냅샷들을 저장
self.history.append(memento)
}
func recoverLastState() { // 가장 최근의 스냅샷을 복원
if let mementoSnapshot: SaveData = self.history.popLast() {
print("최근 저장 상태를 불러옵니다.\n")
mementoSnapshot.recover()
} else {
print("저장 기록이 없습니다.\n")
}
}
}
let originator = Game()
let caretaker = GameDataSystem()
originator.setLevel(level: 5)
originator.setScore(score: 3)
// Originator가 Memento 스냅샷을 생성
let memento = originator.createMemento()
// Memento 스냅샷을 CareTaker에 저장
caretaker.save(memento: memento) // 출력 - Level : 5, Score: 3 상태를 저장합니다.
// 게임을 하다가 레벨과 점수가 이전 저장 했을 때 보다 낮아짐
originator.setLevel(level: 1)
originator.setScore(score: 1)
originator.printCurrentState() // 출력 - 현재 상태 Level : 1, Score: 1
// 레벨과 점수 복구
caretaker.recoverLastState() // 출력 - 최근 저장 상태를 불러옵니다.
originator.printCurrentState() // 출력 - 현재 상태 Level : 5, Score: 3
caretaker.recoverLastState() // 출력 - 저장 기록이 없습니다.