The Command pattern — encapsulating requests as objects, the invoker/command/receiver roles, a Java implementation, undo/redo with command history, queuing/scheduling/logging commands, advantages in event-driven systems, how it decouples sender and receiver, and how it relates to CQRS commands, Runnable and message queues.
Published September 25, 2026
Command turns a request into an object. Once it's an object, you can pass it around, queue it, log it, retry it, schedule it and undo it. In Java you already use it:
Runnable/Callable submitted to an executor;The interview checklist is the roles (client, invoker, command, receiver) and undo/redo.
Short answer: It encapsulates a request as an object, containing everything needed to perform it later: the receiver, the action and the parameters. This lets you parameterise objects with requests, queue or schedule them, log them, and support undo/redo. For example, in a text editor, Copy, Paste and Delete are each a command object that can be executed, stored in a history and reversed.
Learn it in depth → Command Pattern
Short answer: It has four roles:
execute(), and optionally undo().execute() by calling the receiver.execute() without knowing what they do.The request, "what to do, to whom, with what", is now a first-class value.
Short answer:
public interface Command {
void execute();
void undo();
}
public final class TextDocument { // the receiver: the real logic
private final StringBuilder text = new StringBuilder();
public void insert(int pos, String s) { text.insert(pos, s); }
public void delete(int pos, int len) { text.delete(pos, pos + len); }
public String slice(int pos, int len) { return text.substring(pos, pos + len); }
}
public final class InsertText implements Command {
private final TextDocument doc; private final int pos; private final String s;
public InsertText(TextDocument doc, int pos, String s) { this.doc = doc; this.pos = pos; this.s = s; }
public void execute() { doc.insert(pos, s); }
public void undo() { doc.delete(pos, s.length()); }
}
public final class DeleteText implements Command {
private final TextDocument doc; private final int pos, len; private String removed; // state captured for undo
public DeleteText(TextDocument doc, int pos, int len) { this.doc = doc; this.pos = pos; this.len = len; }
public void execute() { removed = doc.slice(pos, len); doc.delete(pos, len); }
public void undo() { doc.insert(pos, removed); }
}
public final class Editor { // the invoker, with history
private final Deque<Command> undo = new ArrayDeque<>(), redo = new ArrayDeque<>();
public void run(Command c) { c.execute(); undo.push(c); redo.clear(); } // a new action invalidates redo
public void undo() { if (!undo.isEmpty()) { Command c = undo.pop(); c.undo(); redo.push(c); } }
public void redo() { if (!redo.isEmpty()) { Command c = redo.pop(); c.execute(); undo.push(c); } }
}
Key points to cover:
LightOnCommand calling light.on() on the Light receiver. It has the same roles as the code above.Short answer:
Short answer:
Short answer: The sender (invoker) only knows the Command interface, and calls execute(). The command knows the receiver and the method to call, and the receiver knows nothing about the sender. So:
With a queue in between, the sender and receiver are also decoupled in time and in process.
Short answer:
Runnable/Callable are command interfaces, and an ExecutorService is the invoker: executor.submit(() -> emailService.send(msg)).PlaceOrderCommand handled by a PlaceOrderHandler) are Commands in which the data object and the handler are separated, often dispatched through a bus.Tasklets, and scheduled jobs (@Scheduled methods wrapped as runnables), are commands with an invoker.public record PlaceOrderCommand(UUID idempotencyKey, UUID customerId, List<LineItem> items) { }
@Component
class PlaceOrderHandler {
@Transactional
public OrderId handle(PlaceOrderCommand cmd) {
return processed.find(cmd.idempotencyKey()) // safe to retry
.orElseGet(() -> orders.place(cmd.customerId(), cmd.items(), cmd.idempotencyKey()));
}
}
Q: Command vs Strategy? A: A Strategy is how to do something (an interchangeable algorithm, called by a context). A Command is what to do (a request object, with a receiver and parameters, that can be stored, queued and undone). Commands are usually one-shot actions. Strategies are reusable algorithms.
Q: How do you implement undo for operations that can't be reversed, like sending an email? A: Use a compensating action: send a correction, cancel a booking, issue a refund. Or delay the irreversible effect (an outbox with a grace period, like "undo send"). Undo often means compensation, not literal reversal, in distributed systems too (sagas).
Q: What is a macro command?
A: A composite command holding a list of commands. execute() runs them in order, and undo() undoes them in reverse order. If one fails midway, undo the already-executed ones to keep it all-or-nothing.
Q: Command vs Memento for undo? A: With Command, each action knows how to reverse itself (store the deltas). With Memento, you snapshot the receiver's state before the action, and restore it on undo. That's simpler for complex state, but uses more memory. Large editors combine them.