Gof의 디자인 패턴 - 메멘토 패턴

Groot·2024년 7월 21일
0

TIL

목록 보기
149/153
post-thumbnail

메멘토 패턴

  • 캡슐화를 지키면서 객체의 내부 상태를 저장하면서 객체가 그 상태로 되돌아올 수 있도록 함

활용성

  • 어떤 객체의 상태에 대한 스냅샷을 저장한 후 나중에 이 상태로 복구해야 할 때
  • 상태를 얻는 데 필요한 직접적인 인터페이스를 두면 그 객체의 구현 세부사항이 드러나기 때문에 캡슐화가 때질 때

구조

요소

  • Memento : 원조본 객체의 내부 상태 저장
  • Originator : 원조본 객체. 메멘토를 생성하여 현재 객체의 상태를 저장하고 메멘토를 사용하여 내부 상태를 복원
  • Caretaker : 메멘토의 보관을 책임지는 보관자. 메멘토의 내용을 검사하거나 그 내용을 건드리지는 않는다.

협력 방법

  • Caretaker객체는 Originator객체에 메멘토 객체를 요청한다.

  • 또한, 요청한 시간을 저장하며, 받는 메멘토 객체를 다시 원조본 객체에게 돌려주는데, 이를 상호작용 다이어그램으로 나타내면 다음과 같다.

  • 메멘토 객체는 수동적이다. 메멘토 객체를 생성한 원조본 객체만이 상태를 설정하고 읽어올 수 있다.

장점

  • 캡슐화 유지
  • Originator 객체의 단순화

단점

  • Originator가 많은 정보를 저장하거나 자주 메멘토를 반환해야 하는 상황이면 오버헤드가 있다.
  • 제한 범위 인터페이스와 광범위 인터페이스를 정의해야 한다.
  • 메멘토 관리비용

예시 코드

// Memento 프로토콜
protocol MementoProtocol {
    var state: [String] { get }
}

// Originator 프로토콜
protocol OriginatorProtocol {
    func createMemento() -> MementoProtocol
    func restore(memento: MementoProtocol)
}

// Caretaker 프로토콜
protocol CaretakerProtocol {
    func saveState(originator: OriginatorProtocol)
    func restoreState(originator: OriginatorProtocol, index: Int)
    func showHistory()
}

// Drawing 클래스
class Drawing: OriginatorProtocol {
    private var shapes: [String] = []

    func addShape(_ shape: String) {
        shapes.append(shape)
    }

    func showShapes() {
        print("현재 도형들: \(shapes.joined(separator: ", "))")
    }

    func createMemento() -> MementoProtocol {
        return DrawingMemento(state: shapes)
    }

    func restore(memento: MementoProtocol) {
        guard let memento = memento as? DrawingMemento else { return }
        self.shapes = memento.state
    }
}

// DrawingMemento 클래스
class DrawingMemento: MementoProtocol {
    let state: [String]

    init(state: [String]) {
        self.state = state
    }
}

// DrawingCaretaker 클래스
class DrawingCaretaker: CaretakerProtocol {
    private var mementos: [MementoProtocol] = []

    func saveState(originator: OriginatorProtocol) {
        mementos.append(originator.createMemento())
    }

    func restoreState(originator: OriginatorProtocol, index: Int) {
        guard index < mementos.count else {
            print("해당 인덱스 \(index)에 저장된 상태가 없습니다.")
            return
        }
        originator.restore(memento: mementos[index])
    }

    func showHistory() {
        for (index, memento) in mementos.enumerated() {
            guard let memento = memento as? DrawingMemento else { continue }
            print("상태 \(index): \(memento.state.joined(separator: ", "))")
        }
    }
}

// 사용 예제
let drawing = Drawing()
let caretaker = DrawingCaretaker()

// 도형 추가 및 상태 저장
drawing.addShape("원")
caretaker.saveState(originator: drawing)

drawing.addShape("사각형")
caretaker.saveState(originator: drawing)

drawing.addShape("삼각형")
caretaker.saveState(originator: drawing)

// 현재 도형 상태 출력
drawing.showShapes()

// 상태 복원
caretaker.restoreState(originator: drawing, index: 1)
drawing.showShapes()

// 상태 복원 이력 출력
caretaker.showHistory()

// 현재 도형들: 원, 사각형, 삼각형
// 현재 도형들: 원, 사각형
// 상태 0: 원
// 상태 1: 원, 사각형
// 상태 2: 원, 사각형, 삼각형

참고

profile
I Am Groot

0개의 댓글