Design Pattern

Command Pattern

Clean Java-only production-ready implementation.


What Problem It Solves

Encapsulate a request as an object. This lets you parameterize clients with different requests, queue or log requests, and support undoable operations.

Where Command Appears in LLD Problems

ProblemCommandQueues or Undo?
Job Scheduler (#32)ScheduleJob, CancelJobQueue (execute later)
Elevator (#3)GoToFloor, OpenDoor, CloseDoorQueue (internal request queue)
Remote Control (general)TurnOn, TurnOff, VolumeUpUndo (last action)
Text Editor / Excel (#56)InsertText, DeleteText, FormatCellUndo/Redo stack
Chess (#14)MovePiece, Castle, PromoteUndo (takeback move)

Implementation

// โ”€โ”€โ”€ EXAMPLE 1 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// WHAT WE ARE IMPLEMENTING:
// A text editing canvas providing complete copy, paste, and multi-level
// action undo/redo tracking.
//
// WHERE THE COMMAND FITS IN:
// Command is the Command interface declaring execute(). CopyCommand is a
// Concrete Command. Editor represents the Receiver. CommandInvoker triggers
// actions.
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
import java.util.ArrayDeque;
import java.util.Deque;

// --- Command interface ---
interface Command {
    void execute();
    void undo();
}

// --- Receiver ---
class TextEditor {
    private final StringBuilder content = new StringBuilder();

    public void append(String text) { content.append(text); }
    public void deleteLast(int length) {
        int start = Math.max(0, content.length() - length);
        content.delete(start, content.length());
    }
    public String getContent() { return content.toString(); }
}

// --- Concrete commands ---
class AppendCommand implements Command {
    private final TextEditor editor;
    private final String text;

    public AppendCommand(TextEditor editor, String text) {
        this.editor = editor;
        this.text = text;
    }

    public void execute() {
        editor.append(text);
    }

    public void undo() {
        editor.deleteLast(text.length());
    }
}

// --- Invoker (with undo stack) ---
class CommandHistory {
    private final Deque<Command> history = new ArrayDeque<>();
    private final Deque<Command> redoStack = new ArrayDeque<>();

    public void execute(Command cmd) {
        cmd.execute();
        history.push(cmd);
        redoStack.clear();
    }

    public void undo() {
        if (!history.isEmpty()) {
            Command cmd = history.pop();
            cmd.undo();
            redoStack.push(cmd);
        }
    }

    public void redo() {
        if (!redoStack.isEmpty()) {
            Command cmd = redoStack.pop();
            cmd.execute();
            history.push(cmd);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        TextEditor editor = new TextEditor();
        CommandHistory history = new CommandHistory();

        history.execute(new AppendCommand(editor, "Hello "));
        history.execute(new AppendCommand(editor, "World!"));

        System.out.println("After: " + editor.getContent());  // Hello World!

        history.undo();
        System.out.println("After undo: " + editor.getContent());  // Hello

        history.redo();
        System.out.println("After redo: " + editor.getContent());  // Hello World!
    }
}

๐Ÿ’ฌReview

Help Us Improve

How helpful was this walkthrough?

Click a star to rate. We actively use this feedback to refine and update our system design content.

Placeholder
Optional but highly appreciated!

Discussion

Share your thoughts, ask questions, or help others.

Loading comments...