Skip to main content

🧩 Command Γ— Memento

βœ… Combined Intent​

  • Use the Command pattern to encapsulate operations (like input) as objects and enable history tracking.
  • Use the Memento pattern to capture and restore the internal state of objects.

This combination enables a structure where you can track what was done and also what the system's state was at that time β€” allowing both command replay and full state rollback.

βœ… Common Use Cases​

  • Applications like text editors or drawing tools where Undo/Redo is essential.
  • Tools that require change tracking (e.g., batch updates, system configurations).
  • When both user actions and internal states need to be recorded and reverted.

βœ… UML Class Diagram​

βœ… Code Example​

// Receiver
class TextEditor {
private content: string = "";

append(text: string) {
this.content += text;
}

deleteLast(n: number) {
this.content = this.content.slice(0, -n);
}

getContent() {
return this.content;
}

save(): EditorMemento {
return new EditorMemento(this.content);
}

restore(memento: EditorMemento) {
this.content = memento.getState();
}
}

// Memento
class EditorMemento {
constructor(private readonly state: string) {}

getState(): string {
return this.state;
}
}

// Command むンターフェース
interface Command {
execute(): void;
undo(): void;
}

// Concrete Command
class TypeCommand implements Command {
private backup: EditorMemento;

constructor(private editor: TextEditor, private text: string) {}

execute(): void {
this.backup = this.editor.save();
this.editor.append(this.text);
}

undo(): void {
this.editor.restore(this.backup);
}
}

// Invoker
class CommandHistory {
private history: Command[] = [];

executeCommand(command: Command) {
command.execute();
this.history.push(command);
}

undo() {
const command = this.history.pop();
if (command) command.undo();
}
}

// 使用例
const editor = new TextEditor();
const history = new CommandHistory();

history.executeCommand(new TypeCommand(editor, "Hello, "));
history.executeCommand(new TypeCommand(editor, "world!"));

console.log(editor.getContent()); // Hello, world!

history.undo();
console.log(editor.getContent()); // Hello,

βœ… Explanation​

  • TextEditor holds the current text and acts as the Receiver, also implementing state snapshot functionality (Memento).
  • TypeCommand represents a text input operation as a Command, and saves a snapshot before execution.
  • CommandHistory stores the list of commands and provides undo() functionality.

By combining these patterns, we can decouple input behavior and state recovery, allowing for a clean and maintainable Undo/Redo system.

βœ… Summary​

  • Command: Encapsulates operations and enables command history.
  • Memento: Captures and restores object state.
  • Their combination allows tracking of both actions and states.
  • Ideal for implementing undoable workflows and reliable state transitions.