Memento

2022. 3. 16. 00:00CSharp/Design Pattern

반응형

구현의 세부 사항을 공개하지 않고 개체의 이전 상태를 저장하고 복원할 수 있는 동작 디자인 패턴

 

 

문제

텍스트 편집기의 기능중에  undo 기능을 만들려고 한다고 가정해 보자

특정 command 를 하게 되면 내용을  history 에 snapshot 형태로 저장할 것이다. 

https://refactoring.guru/design-patterns/memento

 

비공개 필드등은 처리 하기 어렵다.

편집기 관련 class 를 수정 하게 되었을때 개체 상태를 복사하는 class를 함께 변경해야 한다. 

실제 텍스트, 커서 좌표, 현재 스크롤 위치 등을 포함해야 한다.

이러한 값들은 모두 상태가 노출되어야 한다. (public)

 

해결책

상태 스냅샷 생성을 해당 상태의 실제 소유자인 발신자 객체에게 위임

편집기 클래스 자체가 스냅샷 생성

memento 라는 특수 객체에 객체 상태의 복사본을 저장

 

class diagram 

 

https://refactoring.guru/design-patterns/memento

 

 

오리지네이터(Originator) : 내부 상태를 보유하고 있는 일부 객체

케어테이커(Caretaker) : 오리지네이터에 실행 취소

메멘토(Memento) : 케어테이커 에서 변경할 수 없는 상태

 

적용

  • 객체의 이전 상태를 복원할 수 있도록 객체 상태의 스냅샷을 생성하려는 경우
  • 개체의 필드/게터/세터에 대한 직접 액세스가 캡슐화를 위반할 때

예제

public interface ISalesOriginator
{
    SalesMemento SaveMemento();
    void RestoreMemento(SalesMemento memento);

}
/// <summary>
/// The 'Originator' class
/// </summary>
public class SalesOriginator: ISalesOriginator
{
    private string _name;
    private string _phone;
    private double _budget;
    // Gets or sets name
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            Console.WriteLine("Name:   " + _name);
        }
    }
    // Gets or sets phone
    public string Phone
    {
        get { return _phone; }
        set
        {
            _phone = value;
            Console.WriteLine("Phone:  " + _phone);
        }
    }
    // Gets or sets budget
    public double Budget
    {
        get { return _budget; }
        set
        {
            _budget = value;
            Console.WriteLine("Budget: " + _budget);
        }
    }
    // Stores memento
    public SalesMemento SaveMemento()
    {
        Console.WriteLine("\nSaving state --\n");
        return new SalesMemento(_name, _phone, _budget);
    }
    // Restores memento
    public void RestoreMemento(SalesMemento memento)
    {
        Console.WriteLine("\nRestoring state --\n");
        (Name,Phone, Budget) = memento.GetRestore();
    }
}

public interface ISalesMemento
{
    (string Name, string Phone, double Budget) GetRestore();
}

/// <summary>
/// The 'Memento' class
/// </summary>
public class SalesMemento : ISalesMemento
{
    private readonly string _name;
    private readonly string _phone;
    private readonly double _budget;
    // Constructor
    public SalesMemento(string name, string phone, double budget)
    {
        this._name = name;
        this._phone = phone;
        this._budget = budget;
    }
    public string Name => _name;
    public string Phone => _phone;
    public double Budget => _budget;

    public (string Name, string Phone, double Budget ) GetRestore()
    {
        return (this.Name, this.Phone, this.Budget);
    }
}
/// <summary>
/// The 'Caretaker' class
/// </summary>
public class SalesCaretaker
{
    public SalesMemento Memento { get; set; }   
}

사용법

SalesOriginator s = new SalesOriginator();
s.Name = "Noel van Halen";
s.Phone = "(412) 256-0990";
s.Budget = 25000.0;
// Store internal state
SalesCaretaker m = new SalesCaretaker();
m.Memento = s.SaveMemento();
// Continue changing originator
s.Name = "Leo Welch";
s.Phone = "(310) 209-7111";
s.Budget = 1000000.0;
// Restore saved state
s.RestoreMemento(m.Memento);

//output
Name:   Noel van Halen
Phone:  (412) 256-0990
Budget: 25000

Saving state --

Name:   Leo Welch
Phone:  (310) 209-7111
Budget: 1000000

Restoring state --

Name:   Noel van Halen
Phone:  (412) 256-0990
Budget: 25000

 

관련영상

https://youtu.be/Ex6UcUYi5H4

 

 

반응형

'CSharp > Design Pattern' 카테고리의 다른 글

Template Method  (0) 2022.03.18
State  (0) 2022.03.17
Iterator  (0) 2022.03.15
Chain of Responsibility  (0) 2022.03.14
Proxy  (0) 2022.03.11