[Design Pattern] 행동 패턴 8. 메멘토 (Memento)
Table of Contents
메멘토 (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();
}
}