Skip to main content

[Design Pattern] 행동 패턴 8. 메멘토 (Memento)




메멘토 (Memento) #

메멘토

  • 객체의 구현 세부 사항을 공개하지 않으면서(캡슐화), 해당 객체의 이전 상태를 저장하고 복원할 수 있게 해준다.



개념적인 예시 #

// Originator
class Originator
{
    // 상태
    private string _state;

    public Originator(string state)
    {
        this._state = state;
    }

    // 이 비즈니스 로직에서는 상태가 변할 수 있기 때문에 클라이언트는 상태를 따로 저장할 필요가 있다. 
    public void DoSomething()
    {
        Console.WriteLine("Originator: I'm doing something important.");
        
        // 상태가 변한다. 
        this._state = GenerateRandomString(30);
    }

    private string GenerateRandomString(int length = 10)
    {
        string allowedSymbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        string result = string.Empty;

        while (length > 0)
        {
            result += allowedSymbols[new Random().Next(0, allowedSymbols.Length)];

            Thread.Sleep(12);

            length--;
        }

        return result;
    }

    // 현재 상태를 메멘토 안에다가 저장한다.
    public IMemento Save()
    {
        return new ConcreteMemento(this._state);
    }

    // 메멘토 안에 있는 상태를 다시 복원한다. 
    public void Restore(IMemento memento)
    {
        if (!(memento is ConcreteMemento))
        {
            throw new Exception("Unknown memento class " + memento.ToString());
        }

        this._state = memento.GetState();
    }
}

// 메멘토
public interface IMemento
{
    string GetName();
    string GetState();
    DateTime GetDate();
}

class ConcreteMemento : IMemento
{
    private string _state;
    private DateTime _date;

    public ConcreteMemento(string state)
    {
        this._state = state;
        this._date = DateTime.Now;
    }
    
    // Originator가 이 메서드를 사용해서 상태를 복원한다. 
    public string GetState()
    {
        return this._state;
    }
    
    // Caretaker가 아래 메서드들을 사용해서 메타데이터를 출력한다. 
    public string GetName()
    {
        return $"{this._date} / ({this._state.Substring(0, 9)})...";
    }

    public DateTime GetDate()
    {
        return this._date;
    }
}

// Caretaker 
// Originator의 상태를 모른다. 구체화된 메멘토 클래스도 모른다. 
class Caretaker
{
    private List<IMemento> _mementos = new List<IMemento>();
    private Originator _originator = null;

    public Caretaker(Originator originator)
    {
        this._originator = originator;
    }

    // Originator의 상태를 저장한다. 
    public void Backup()
    {
        this._mementos.Add(this._originator.Save());
    }

    // Originator의 상태를 복원한다. 
    public void Undo()
    {
        if (this._mementos.Count == 0) return;

        var memento = this._mementos.Last();
        this._mementos.Remove(memento);

        try
        {
            this._originator.Restore(memento);
        }
        catch (Exception)
        {
            this.Undo();
        }
    }
    
    public void ShowHistory()
    {
        foreach (var memento in this._mementos)
        {
            Console.WriteLine(memento.GetName());
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        Originator originator = new Originator("Super-duper-super-puper-super.");
        Caretaker caretaker = new Caretaker(originator);

        caretaker.Backup();
        originator.DoSomething();

        caretaker.Backup();
        originator.DoSomething();

        caretaker.Backup();
        originator.DoSomething();

        // 히스토리
        caretaker.ShowHistory();

        // 복원
        caretaker.Undo();
        caretaker.Undo();
    }
}



References #