Что такое паттерн "Хранитель" (Memento)
Хранитель — поведенческий паттерн проектирования, который позволяет сохранять и восстанавливать внутреннее состояние объекта без нарушения его инкапсуляции. Это особенно полезно для реализации функции отмены (undo) и истории изменений.
Представьте текстовый редактор, который позволяет отменять последние изменения. Паттерн Хранитель позволяет сохранить состояние документа до изменений и восстановить его при необходимости.
Преимущества паттерна «Хранитель»
- Позволяет сохранять и восстанавливать состояние объекта.
- Сохраняет инкапсуляцию, не раскрывая внутренние детали.
- Упрощает реализацию функционала undo/redo.
Пример:
- Объект-источник (Originator) хранит состояние.
- Хранитель (Memento) сохраняет состояние.
- Опекун (Caretaker) управляет сохранением и восстановлением состояний.
Где применяется паттерн «Хранитель»?
- Текстовые редакторы и IDE с поддержкой undo/redo.
- Игры с сохранением прогресса.
- Любые системы, где важна история изменений.
Пример реализации на JavaScript
// Хранитель — хранит состояние class Memento { constructor(state) { this.state = state; } getState() { return this.state; } } // Объект-источник — сохраняет состояние и может его восстанавливать class Originator { constructor() { this.state = ""; } setState(state) { console.log(`Установка состояния: ${state}`); this.state = state; } save() { console.log("Сохраняем состояние."); return new Memento(this.state); } restore(memento) { this.state = memento.getState(); console.log(`Восстановлено состояние: ${this.state}`); } } // Опекун — управляет сохранениями class Caretaker { constructor(originator) { this.originator = originator; this.mementos = []; } backup() { this.mementos.push(this.originator.save()); } undo() { if (!this.mementos.length) return; const memento = this.mementos.pop(); this.originator.restore(memento); } } // Использование const originator = new Originator(); const caretaker = new Caretaker(originator); originator.setState("Состояние 1"); caretaker.backup(); originator.setState("Состояние 2"); caretaker.backup(); originator.setState("Состояние 3"); caretaker.undo(); // Восстановит "Состояние 2" caretaker.undo(); // Восстановит "Состояние 1"
Когда стоит использовать паттерн «Хранитель»?
- Требуется сохранять состояние объекта для возможного восстановления.
- Необходимо реализовать функционал undo/redo.
- Важно сохранить инкапсуляцию объекта.
Отличие от других паттернов
- В отличие от снимка (Snapshot), хранитель сохраняет состояние без нарушения инкапсуляции.
- Не следует путать с прототипом — Хранитель не создаёт копии объекта, а сохраняет его внутреннее состояние.
Плюсы паттерна
- Сохраняет инкапсуляцию объекта.
- Упрощает реализацию undo/redo.
- Позволяет легко управлять историей изменений.
Минусы паттерна
- Может увеличивать использование памяти при большом количестве сохранений.
- Усложняет структуру кода.
- Требует грамотного управления хранением состояний.