Command Pattern — Design Patterns

Command membungkus permintaan (apa yang harus dilakukan + data) ke dalam object. Object itu bisa disimpan, diantri, di-undo, direplay, atau dikirim ke…

Command membungkus permintaan (apa yang harus dilakukan + data) ke dalam object. Object itu bisa disimpan, diantri, di-undo, direplay, atau dikirim ke worker/server.

Problem yang diselesaikan:

Kadang kamu butuh lebih dari sekadar "eksekusi sekarang". Kamu butuh:

Semua ini butuh aksi yang bisa dibawa-bawa sebagai data — itulah Command.

Implementasi minimal — undo/redo untuk text editor:

class InsertTextCommand {
  constructor(editor, text, position) {
    this.editor = editor;
    this.text = text;
    this.position = position;
  }
  execute() {
    this.editor.insert(this.position, this.text);
  }
  undo() {
    this.editor.delete(this.position, this.text.length);
  }
}

class DeleteTextCommand {
  constructor(editor, position, length) {
    this.editor = editor;
    this.position = position;
    this.length = length;
    this.deletedText = null; // diisi saat execute
  }
  execute() {
    this.deletedText = this.editor.content.slice(this.position, this.position + this.length);
    this.editor.delete(this.position, this.length);
  }
  undo() {
    this.editor.insert(this.position, this.deletedText);
  }
}

// Invoker / history
class CommandHistory {
  constructor() {
    this.done = [];
    this.undone = [];
  }
  run(command) {
    command.execute();
    this.done.push(command);
    this.undone = []; // branch baru → buang redo future
  }
  undo() {
    const cmd = this.done.pop();
    if (cmd) { cmd.undo(); this.undone.push(cmd); }
  }
  redo() {
    const cmd = this.undone.pop();
    if (cmd) { cmd.execute(); this.done.push(cmd); }
  }
}

const history = new CommandHistory();
history.run(new InsertTextCommand(editor, "Halo ", 0));
history.run(new InsertTextCommand(editor, "dunia", 5));
history.undo(); // "Halo "
history.redo(); // "Halo dunia"

Kunci Command: tiap aksi adalah object yang tahu cara execute() dan (opsional) undo().

Dunia nyata di ekosistem JS/Laravel:

Command + Macro:

class MacroCommand {
  constructor(commands) { this.commands = commands; }
  execute() { for (const c of this.commands) c.execute(); }
  undo()    { for (const c of [...this.commands].reverse()) c.undo(); }
}

Rekaman macro Photoshop, Excel, atau shortcut editor tingkat lanjut — MacroCommand yang kumpulin commands selama recording.

Kapan pakai:

Kapan JANGAN pakai:

Trade-off:

Command bagus untuk decoupling in time (kapan eksekusi vs kapan dibuat) dan in space (siapa buat vs siapa eksekusi). Kekurangannya: menaikkan jumlah class/object dan perlu disiplin desain undo() yang benar — banyak bug memento terjadi di sini.

Yang akan kamu pelajari