Коротка відповідь
middleMemento — це патерн, що зберігає внутрішній стан об’єкта без порушення інкапсуляції, дозволяючи відновити його у майбутньому. У TS це реалізується через клас `Memento` з приватним полем state, а `Originator` створює та відновлює його. Приклад: `const snap = originator.save(); … originator.restore(snap);`
Повне пояснення
1. Що це і навіщо
Memento (Снимок) – патерн збереження стану, що дозволяє відновити об’єкт у попередньому стані без розкриття його внутрішньої структури. Підходить для undo/redo, транзакційних зворотніх дій.
2. Принцип роботи / алгоритм
- Originator – об’єкт, стан якого треба зберегти.
- Memento – контейнер із приватним полем
state(може бути об’єктом, JSON‑строкою тощо). - Caretaker – управляє збереженнями, не читаючи
state.
Алгоритм: Originator викликає createMemento(), Caretaker зберігає його; при потребі Originator викликає restore(memento).
3. Реалізація (JS / TS)
- Базова реалізація
class Memento {
constructor(private state: any) {}
getState() { return this.state; }
}
class Originator {
private state: any;
setState(state: any) { this.state = state; }
createMemento() { return new Memento(this.state); }
restore(m: Memento) { this.state = m.getState(); }
}
- Веб‑dev приклад – редактор тексту з undo/redo
class TextEditor {
private content = "";
private history: Memento[] = [];
write(text: string) { this.content += text; }
save() { this.history.push(new Memento(this.content)); }
undo() {
const m = this.history.pop();
if (m) this.content = m.getState();
}
}
- Новачковий спрощений – збереження числа
class Counter {
private value = 0;
inc() { this.value++; }
getMemento() { return new Memento(this.value); }
setMemento(m: Memento) { this.value = m.getState(); }
}
4. Тестування (Jest або Vitest)
test('undo restores previous state', () => {
const editor = new TextEditor();
editor.write('a'); editor.save();
editor.write('b');
editor.undo();
expect(editor.getContent()).toBe('a');
});
5. Проблеми та edge cases
- Неправильне використання ролей – Caretaker читає
stateчерез Memento, порушуючи інкапсуляцію. - Зайва абстракція – створення Memento для простих об’єктів, що не потребують збереження.
- Cyclical dependencies – Originator залежить від Memento, а Memento зберігає Originator, що створює цикл.
- Плутанина з Prototype – обидва патерни створюють копії, але Memento не змінює оригінал.
- Performance‑пастки – копіювання великих об’єктів у Memento збільшує пам’ять і час.
6. Оптимізація та продуктивність
- Використовувати deep copy лише при необхідності; іноді достатньо shallow.
- Зберігати diff замість повного стану, щоб зменшити пам’ять.
- Підтримувати lazy restoration – відновлювати лише при виклику.
7. Без JS / архітектурні альтернативи
- У React можна зберігати стан у Redux‑store і використовувати middleware для історії.
- У CSS можна застосовувати
:focus-visibleабоanimation-play-stateдля збереження стилів. - У HTML атрибут
data-*може тримати попередні значення.
8. Cheatsheet + follow-up
- Cheatsheet: Originator → createMemento() / restore(m); Caretaker → store/restore; Memento → getState().
- Interview Q1: Як Memento відрізняється від Prototype?
- Interview Q2: Які ризики пов’язані з копіюванням великих об’єктів у Memento?