Memento
- Use for implementing undo mechanism
Classical Structure
Problem
- Violates Single Responsibility Principle. Single Responsibility Principle means every class should have single responsibility. eg In restaurant, waiter is responsible only for taking order and not for cooking, billing etc.
- Editor class has 2 responsibilities: State management, Editor features
public class Editor
{
private string content = string.Empty;
Stack<EditorState> prevStates = new Stack<EditorState>();
public string Content {
get => content;
set {
prevStates.Push(new EditorState(content));
content = value;
}
}
public void Restore()
{
var state = prevStates.Pop();
content = state.Content;
}
}
public class EditorState
{
public string Content { get; init; }
public EditorState(string content)
{
this.Content = content;
}
}
public class Program
{
static void Main(string[] args)
{
Editor editor = new Editor();
editor.Content = "a";
editor.Content = "b";
editor.Content = "c";
editor.Restore();
editor.Restore();
Console.WriteLine(editor.Content);
}
}
Solution
- Move state management from Editor to another class (History).
- History class will be responsible for state management. Keep track of changes in state of editor
public class EditorState
{
public string Content { get; init; }
public EditorState(string content)
{
this.Content = content;
}
}
public class History
{
Stack<EditorState> states = new Stack<EditorState>();
public void Push(EditorState state)
{
states.Push(state);
}
public EditorState Pop()
{
return states.Pop();
}
}
public class Editor
{
public string Content { get; set; }
public EditorState CreateState()
{
return new EditorState(Content);
}
public void Restore(EditorState state)
{
Content = state.Content;
}
}
public class Program
{
static void Main(string[] args)
{
Editor editor = new Editor();
History history = new History();
editor.Content = "a";
history.Push(editor.CreateState());
editor.Content = "b";
history.Push(editor.CreateState());
editor.Content = "c";
editor.Restore(history.Pop());
editor.Restore(history.Pop());
Console.WriteLine(editor.Content);
}
}
Example Structure
Example Code