SwadhyAI Notes

All Low-Level Design notes

Behavioral · Gang of Four

Command

Command is a behavioral pattern that turns an action into an object with execute (and often undo). History becomes a stack of commands instead of scattered field snapshots inside Game.

Example: a knight slides to e5, then the player hits undo. If Game mutates the board in place, undo is a pile of remembered fields. If the move is a with execute and undo, history is a stack: pop, undo, done.

01

Name the action

PlayMove, Resign, TurnOn — a verb as a type, not a string.

02

Give it execute

The invoker only calls execute. It does not switch on names.

03

Give it undo

Store enough to reverse: from, to, captured piece.

04

Keep a stack

execute pushes. undo pops. redo is a second stack.

The contrast interviewers mix up

Command vs Memento

Command remembers an action and how to reverse it. Memento remembers a snapshot of state and how to restore it, without knowing what changed. Chess often uses both: execute applies the move and may keep a small memento if reverse is messy (castling, en passant). Prefer Command when the inverse is clear. Prefer Memento when you would rather not invert at all.

Command

Store the verb

  • API: execute / undo
  • Holds receiver + arguments
  • never peeks at Board fields
  • Best when PlayMove can invert through the public API

Memento

Store the picture

  • API: save / restore
  • Caretaker holds a sealed snapshot
  • Originator alone can read the fields
  • Best when inverting every keystroke is silly

If undo does board.setGrid(copy), you leaked representation and reinvented Memento badly. Either the command reverses through the board’s public API, or you take a real memento the board creates.

Java: a chess move you can take back

The is Board. The command stores captured so undo can put it back. Game is only an .

java
interface MoveCommand {
  void execute();
  void undo();
}

class PlayMove implements MoveCommand {
  private final Board board;
  private final Square from, to;
  private Piece captured;

  public void execute() {
    captured = board.pieceAt(to);
    board.move(from, to);
  }

  public void undo() {
    board.move(to, from);
    if (captured != null) board.place(to, captured);
  }
}

class Game {
  private final Deque<MoveCommand> history = new ArrayDeque<>();
  private final Deque<MoveCommand> redo = new ArrayDeque<>();

  void play(MoveCommand move) {
    move.execute();
    history.push(move);
    redo.clear();
  }

  void undo() {
    if (history.isEmpty()) return;
    MoveCommand move = history.pop();
    move.undo();
    redo.push(move);
  }

  void redo() {
    if (redo.isEmpty()) return;
    play(redo.pop());
  }
}

When to use Command

Queue later

A task scheduler is Command plus a clock: the object is the work, the queue is the when. That is the LLD shape. The HLD note is workers, visibility timeouts, and poison messages — keep those sentences out of this round.

Replay and log

Audit “what the player did” by storing commands, not by dumping the whole Game. A remote control’s buttons are commands you can record as a .

Commands vs queries

Do not confuse this pattern with CQRS naming. A Command object is a verb you can store. A query method should not mutate. Both ideas can live in one design; they are not the same sentence.

A switch on action names

execute(String name) with case "MOVE" is not Command. You have a stringly-typed procedure. The action has to be a type you can store.

Undo that peeks into the board

If undo assigns board.grid = oldGrid, you leaked internals. Reverse through the API, or let the board save a memento.

Forty-five minutes: chess undo

Say the variation first: “moves must be reversible.” Then draw PlayMove, Resign, and Game as invoker. Do not start with the word Command. If they ask about castling, admit the inverse is messy and take a memento from Board for that move only. That distinction shows you know both patterns.

  1. Step 1Board, Piece, Square. PlayMove holds from, to, captured.
  2. Step 2execute / undo through Board’s public API. Game only has a Deque.
  3. Step 3Redo as a second stack. A new play() clears redo.
  4. Step 4Follow-up: macros, or “what if undo cannot invert?” → Memento.

Java: a macro is still one command

Castle, or “paint these three cells,” is a list. execute runs forward. undo runs backward. The invoker still only calls execute.

java
class Macro implements MoveCommand {
  private final List<MoveCommand> steps;
  Macro(List<MoveCommand> steps) { this.steps = List.copyOf(steps); }

  public void execute() {
    steps.forEach(MoveCommand::execute);
  }

  public void undo() {
    ListIterator<MoveCommand> it = steps.listIterator(steps.size());
    while (it.hasPrevious()) it.previous().undo();
  }
}

Remote control

Buttons hold Command, not Light. Swap the slot, the remote class does not change. That is the textbook picture; chess is the interview picture.

When a method is enough

If there is no queue, no undo, and no log, a method on Game is honest. Command is for storing the verb.

Do not build a command bus

A frameworky CommandBus with handlers and middleware is HLD-shaped. In LLD, an interface and a stack are enough.

Nearby in LLD