定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后恢复对象到保存的状态

类比:就像你在玩游戏时保存进度,你可以在以后任何时候加载这个进度,恢复到保存时的状态。

应用场景

  • 保存对象的快照,以便以后恢复
  • 需要实现撤销操作

优缺点

  • 优点
    • 提供了恢复状态的机制而不需要破坏封装性
    • 简化了系统的状态恢复功能
  • 缺点
    • 可能占用大量资源(内存或磁盘空间)
    • 复杂状态恢复时,备忘录的实现可能比较复杂

实现代码

// 备忘录接口
interface Memento {
  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})`;
  }
 
  public getDate(): string {
    return this.date;
  }
}
 
// 发起人
class Originator {
  private state: string;
 
  constructor(state: string) {
    this.state = state;
    console.log(`Originator: My initial state is: ${state}`);
  }
 
  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
      .from({ length }, () => 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 as ConcreteMemento).getState();
    console.log(`Originator: My state has changed to: ${this.state}`);
  }
}
 
// 管理者
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();