Ответ
Паттерн Memento позволяет сохранять и восстанавливать внутреннее состояние объекта, не нарушая его инкапсуляцию. Это основа для реализации функциональности Undo/Redo, снапшотов или контрольных точек.
Классическая реализация на C#:
// 1. Хранитель (Memento) — иммутабельный объект, хранящий снимок состояния.
public class TextMemento
{
public string Content { get; }
public DateTime CreatedAt { get; }
public TextMemento(string content)
{
Content = content;
CreatedAt = DateTime.UtcNow;
}
}
// 2. Создатель (Originator) — объект, состояние которого нужно сохранять.
public class TextDocument
{
private string _content;
public string Content
{
get => _content;
set
{
Console.WriteLine($"Document content changed to: {value}");
_content = value;
}
}
// Создать снимок текущего состояния
public TextMemento CreateMemento()
{
return new TextMemento(_content);
}
// Восстановить состояние из снимка
public void RestoreMemento(TextMemento memento)
{
_content = memento.Content;
Console.WriteLine($"Document restored to state from {memento.CreatedAt}");
}
}
// 3. Опекун (Caretaker) — управляет историей снимков.
public class HistoryTracker
{
private readonly Stack<TextMemento> _history = new Stack<TextMemento>();
public void SaveState(TextDocument document)
{
_history.Push(document.CreateMemento());
}
public void Undo(TextDocument document)
{
if (_history.Count > 0)
{
document.RestoreMemento(_history.Pop());
}
}
}
// Пример использования
class Program
{
static void Main()
{
var doc = new TextDocument();
var history = new HistoryTracker();
doc.Content = "Version 1";
history.SaveState(doc); // Сохраняем
doc.Content = "Version 2";
history.SaveState(doc); // Сохраняем
doc.Content = "Version 3";
Console.WriteLine($"Current: {doc.Content}"); // Version 3
history.Undo(doc); // Откат к Version 2
Console.WriteLine($"After undo: {doc.Content}"); // Version 2
history.Undo(doc); // Откат к Version 1
Console.WriteLine($"After second undo: {doc.Content}"); // Version 1
}
}
Почему это важно:
- Инкапсуляция: Объект
TextDocumentсам создаёт и читает снимки, его внутреннее представление состояния (_content) остаётся приватным. - Гибкость: Опекун (
HistoryTracker) может хранить историю в стеке (для Undo), очереди или любом другом хранилище, не влияя на создателя. - Расширяемость: В снимок можно добавлять метаданные (например, timestamp), а также реализовать сжатие или сериализацию состояния для сохранения на диск.