메멘토 패턴은 행동 디자인 패턴입니다. 이 패턴은 객체 상태의 스냅숏을 만든 후 나중에 복원할 수 있도록 합니다.
메멘토는 함께 작동하는 객체의 내부 구조와 스냅숏들 내부에 보관된 데이터를 손상하지 않습니다.
복잡도:
인기도:
사용 사례들: 메멘토의 원칙은 직렬화를 사용하여 달성할 수 있으며, 이는 C 코드에서 매우 일반적입니다. 직렬화는 객체 상태의 스냅숏을 만드는 유일한 또는 가장 효율적인 방법은 아니나 다른 객체로부터 오리지네이터의 구조를 보호하면서 상태 백업을 저장할 수 있도록 합니다.
개념적인 예시
이 예시는 메멘토 패턴의 구조를 보여주고 다음 질문에 중점을 둡니다:
패턴은 어떤 클래스들로 구성되어 있나요?
이 클래스들은 어떤 역할을 하나요?
패턴의 요소들은 어떻게 서로 연관되어 있나요?
Program.cs: 개념적인 예시
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace RefactoringGuru.DesignPatterns.Memento.Conceptual
{
// The Originator holds some important state that may change over time. It
// also defines a method for saving the state inside a memento and another
// method for restoring the state from it.
class Originator
{
// For the sake of simplicity, the originator's state is stored inside a
// single variable.
private string _state;
public Originator(string state)
{
this._state = state;
Console.WriteLine("Originator: My initial state is: " + state);
}
// The Originator's business logic may affect its internal state.
// Therefore, the client should backup the state before launching
// methods of the business logic via the save() method.
public void DoSomething()
{
Console.WriteLine("Originator: I'm doing something important.");
this._state = this.GenerateRandomString(30);
Console.WriteLine($"Originator: and my state has changed to: {_state}");
}
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;
}
// Saves the current state inside a memento.
public IMemento Save()
{
return new ConcreteMemento(this._state);
}
// Restores the Originator's state from a memento object.
public void Restore(IMemento memento)
{
if (!(memento is ConcreteMemento))
{
throw new Exception("Unknown memento class " + memento.ToString());
}
this._state = memento.GetState();
Console.Write($"Originator: My state has changed to: {_state}");
}
}
// The Memento interface provides a way to retrieve the memento's metadata,
// such as creation date or name. However, it doesn't expose the
// Originator's state.
public interface IMemento
{
string GetName();
string GetState();
DateTime GetDate();
}
// The Concrete Memento contains the infrastructure for storing the
// Originator's state.
class ConcreteMemento : IMemento
{
private string _state;
private DateTime _date;
public ConcreteMemento(string state)
{
this._state = state;
this._date = DateTime.Now;
}
// The Originator uses this method when restoring its state.
public string GetState()
{
return this._state;
}
// The rest of the methods are used by the Caretaker to display
// metadata.
public string GetName()
{
return $"{this._date} / ({this._state.Substring(0, 9)})...";
}
public DateTime GetDate()
{
return this._date;
}
}
// The Caretaker doesn't depend on the Concrete Memento class. Therefore, it
// doesn't have access to the originator's state, stored inside the memento.
// It works with all mementos via the base Memento interface.
class Caretaker
{
private List<IMemento> _mementos = new List<IMemento>();
private Originator _originator = null;
public Caretaker(Originator originator)
{
this._originator = originator;
}
public void Backup()
{
Console.WriteLine("\nCaretaker: Saving Originator's state...");
this._mementos.Add(this._originator.Save());
}
public void Undo()
{
if (this._mementos.Count == 0)
{
return;
}
var memento = this._mementos.Last();
this._mementos.Remove(memento);
Console.WriteLine("Caretaker: Restoring state to: " + memento.GetName());
try
{
this._originator.Restore(memento);
}
catch (Exception)
{
this.Undo();
}
}
public void ShowHistory()
{
Console.WriteLine("Caretaker: Here's the list of mementos:");
foreach (var memento in this._mementos)
{
Console.WriteLine(memento.GetName());
}
}
}
class Program
{
static void Main(string[] args)
{
// Client code.
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();
Console.WriteLine();
caretaker.ShowHistory();
Console.WriteLine("\nClient: Now, let's rollback!\n");
caretaker.Undo();
Console.WriteLine("\n\nClient: Once more!\n");
caretaker.Undo();
Console.WriteLine();
}
}
}
Output.txt: 실행 결과
Originator: My initial state is: Super-duper-super-puper-super.
Caretaker: Saving Originator's state...
Originator: I'm doing something important.
Originator: and my state has changed to: oGyQIIatlDDWNgYYqJATTmdwnnGZQj
Caretaker: Saving Originator's state...
Originator: I'm doing something important.
Originator: and my state has changed to: jBtMDDWogzzRJbTTmEwOOhZrjjBULe
Caretaker: Saving Originator's state...
Originator: I'm doing something important.
Originator: and my state has changed to: exoHyyRkbuuNEXOhhArKccUmexPPHZ
Caretaker: Here's the list of mementos:
12.06.2018 15:52:45 / (Super-dup...)
12.06.2018 15:52:46 / (oGyQIIatl...)
12.06.2018 15:52:46 / (jBtMDDWog...)
Client: Now, let's rollback!
Caretaker: Restoring state to: 12.06.2018 15:52:46 / (jBtMDDWog...)
Originator: My state has changed to: jBtMDDWogzzRJbTTmEwOOhZrjjBULe
Client: Once more!
Caretaker: Restoring state to: 12.06.2018 15:52:46 / (oGyQIIatl...)
Originator: My state has changed to: oGyQIIatlDDWNgYYqJATTmdwnnGZQj
다른 언어로 작성된 메멘토