Снимок — это поведенческий паттерн, позволяющий делать снимки внутреннего состояния объектов, а затем восстанавливать их.
При этом Снимок не раскрывает подробностей реализации объектов, и клиент не имеет доступа к защищённой информации объекта.
Сложность:
Популярность:
Применимость: Снимок на TypeScript чаще всего реализуют с помощью сериализации. Но это не единственный, да и не самый эффективный метод сохранения состояния объектов во время выполнения программы.
Концептуальный пример
Этот пример показывает структуру паттерна Снимок , а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
index.ts: Пример структуры паттерна
/**
* Создатель содержит некоторое важное состояние, которое может со временем
* меняться. Он также объявляет метод сохранения состояния внутри снимка и метод
* восстановления состояния из него.
*/
class Originator {
/**
* Для удобства состояние создателя хранится внутри одной переменной.
*/
private state: string;
constructor(state: string) {
this.state = state;
console.log(`Originator: My initial state is: ${state}`);
}
/**
* Бизнес-логика Создателя может повлиять на его внутреннее состояние.
* Поэтому клиент должен выполнить резервное копирование состояния с помощью
* метода save перед запуском методов бизнес-логики.
*/
public doSomething(): void {
console.log('Originator: I\'m doing something important.');
this.state = this.generateRandomString(30);
console.log(`Originator: and my state has changed to: ${this.state}`);
}
private generateRandomString(length: number = 10): string {
const charSet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
return Array
.apply(null, { length })
.map(() => charSet.charAt(Math.floor(Math.random() * charSet.length)))
.join('');
}
/**
* Сохраняет текущее состояние внутри снимка.
*/
public save(): Memento {
return new ConcreteMemento(this.state);
}
/**
* Восстанавливает состояние Создателя из объекта снимка.
*/
public restore(memento: Memento): void {
this.state = memento.getState();
console.log(`Originator: My state has changed to: ${this.state}`);
}
}
/**
* Интерфейс Снимка предоставляет способ извлечения метаданных снимка, таких как
* дата создания или название. Однако он не раскрывает состояние Создателя.
*/
interface Memento {
getState(): string;
getName(): string;
getDate(): string;
}
/**
* Конкретный снимок содержит инфраструктуру для хранения состояния Создателя.
*/
class ConcreteMemento implements Memento {
private state: string;
private date: string;
constructor(state: string) {
this.state = state;
this.date = new Date().toISOString().slice(0, 19).replace('T', ' ');
}
/**
* Создатель использует этот метод, когда восстанавливает своё состояние.
*/
public getState(): string {
return this.state;
}
/**
* Остальные методы используются Опекуном для отображения метаданных.
*/
public getName(): string {
return `${this.date} / (${this.state.substr(0, 9)}...)`;
}
public getDate(): string {
return this.date;
}
}
/**
* Опекун не зависит от класса Конкретного Снимка. Таким образом, он не имеет
* доступа к состоянию создателя, хранящемуся внутри снимка. Он работает со
* всеми снимками через базовый интерфейс Снимка.
*/
class Caretaker {
private mementos: Memento[] = [];
private originator: Originator;
constructor(originator: Originator) {
this.originator = originator;
}
public backup(): void {
console.log('\nCaretaker: Saving Originator\'s state...');
this.mementos.push(this.originator.save());
}
public undo(): void {
if (!this.mementos.length) {
return;
}
const memento = this.mementos.pop();
console.log(`Caretaker: Restoring state to: ${memento.getName()}`);
this.originator.restore(memento);
}
public showHistory(): void {
console.log('Caretaker: Here\'s the list of mementos:');
for (const memento of this.mementos) {
console.log(memento.getName());
}
}
}
/**
* Клиентский код.
*/
const originator = new Originator('Super-duper-super-puper-super.');
const caretaker = new Caretaker(originator);
caretaker.backup();
originator.doSomething();
caretaker.backup();
originator.doSomething();
caretaker.backup();
originator.doSomething();
console.log('');
caretaker.showHistory();
console.log('\nClient: Now, let\'s rollback!\n');
caretaker.undo();
console.log('\nClient: Once more!\n');
caretaker.undo();
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: qXqxgTcLSCeLYdcgElOghOFhPGfMxo
Caretaker: Saving Originator's state...
Originator: I'm doing something important.
Originator: and my state has changed to: iaVCJVryJwWwbipieensfodeMSWvUY
Caretaker: Saving Originator's state...
Originator: I'm doing something important.
Originator: and my state has changed to: oSUxsOCiZEnohBMQEjwnPWJLGnwGmy
Caretaker: Here's the list of mementos:
2019-02-17 15:14:05 / (Super-dup...)
2019-02-17 15:14:05 / (qXqxgTcLS...)
2019-02-17 15:14:05 / (iaVCJVryJ...)
Client: Now, let's rollback!
Caretaker: Restoring state to: 2019-02-17 15:14:05 / (iaVCJVryJ...)
Originator: My state has changed to: iaVCJVryJwWwbipieensfodeMSWvUY
Client: Once more!
Caretaker: Restoring state to: 2019-02-17 15:14:05 / (qXqxgTcLS...)
Originator: My state has changed to: qXqxgTcLSCeLYdcgElOghOFhPGfMxo
Снимок на других языках программирования