← Back to list

Command Design Pattern

The Command Design Pattern is a behavioral pattern that turns a request into a stand-alone object. This object contains all the information…

Kandaanusha · 2026-02-04 15:08 · 0 claps · 3.9 min read
#low-level-design #command-design-pattern #java #software-design-patterns
Open on Medium ↗
Wiki topics: 🥊 · Combat Sports

Command Design Pattern

The Command Design Pattern is a behavioral pattern that turns a request into a stand-alone object. This object contains all the information about the request: the method being called, the object it belongs to, and the parameters.

Think of it like a restaurant: The waiter (Invoker) takes your order (Command) and puts it on the counter. The chef (Receiver) then picks up the order and cooks it. The waiter doesn’t need to know how to cook; they just need to trigger the “order” object.

Core Components

The pattern relies on four main pillars to decouple the sender from the receiver:

  1. Command Interface: Usually a simple interface with an execute() method.
  2. Concrete Command: Implements the interface and links a specific action to a Receiver.
  3. Receiver: The object that actually knows how to perform the business logic (the “Chef”).
  4. Invoker: The object that triggers the command (the “Waiter” or a “Button”).
  5. Client: Creates the Concrete Command and assigns it to the Receiver.

Why Use the Command Pattern?

The primary goal is decoupling. It separates the object that invokes the operation (the “Invoker”) from the object that knows how to perform it (the “Receiver”).

Problems It Solves

  1. Request Parameterization: You can pass different commands to a single button or menu item without the button needing to know what each command does.
  2. Queueing and Scheduling: Since commands are objects, you can put them in a list or a queue to be executed later (like a thread pool or a job scheduler).
  3. Undo/Redo Functionality: By storing a history of command objects, you can iterate backward through them to reverse operations.
  4. Macro Commands: You can combine multiple commands into a single “composite” command (e.g., a “Start System” command that turns on lights, starts the PC, and opens the browser).

Real Use Cases

Here are the most common real-world applications:

1. GUI Buttons and Menu Items

This is the “classic” use case. In frameworks like Java Swing or JavaFX, an Action or EventHandler is essentially a command.

  • The Problem: A Button class shouldn't know what happens when it’s clicked (e.g., "Save," "Print," or "Exit").
  • The Solution: The button holds a reference to a Command object. When clicked, it just calls command.execute(). This allows the same Button class to be reused for thousands of different actions.

2. Thread Pools and Job Queues

In high-scale backends, you often don’t want to execute a heavy task (like generating a PDF or sending 10,000 emails) immediately upon a user request.

  • The Mechanism: You wrap the task into a Command object (in Java, often implementing Runnable or Callable) and drop it into a PriorityQueue.
  • The Result: Worker threads pick up these “Command” objects and execute them whenever they have the capacity.

3. Text Editors (The Undo/Redo Engine)

Software like IntelliJ, VS Code, or Microsoft Word relies heavily on this.

  • How it works: Every action — typing a character, deleting a block, or formatting text — is a Command object stored in a Stack.
  • Undo: Pop the last command from the “Done” stack and call its undo() method.
  • Redo: Push that same command onto a “Redo” stack so it can be re-executed.

4. Transaction Management (Databases & Banking)

When performing operations that must be “all or nothing,” the Command pattern tracks the steps.

  • The Use Case: A bank transfer involves (1) deducting from Account A and (2) adding to Account B.
  • The Logic: Each step is wrapped in a command. If step 2 fails, the system iterates through the history of commands and calls undo() on everything that already succeeded to prevent data corruption.

When to use it vs. a simple Method Call?

Use Command if you find yourself writing massive switch or if-else blocks to decide which action to take based on a user input. If you just need to call a method and move on, stick to the simple way—don't over-engineer!

Example in Java: Undo/Redo

Using the Command Pattern turns actions into first-class objects, which is exactly how IDEs and word processors manage complex state changes without losing their minds.

Here is a breakdown of how this looks in Java, specifically focusing on the “Undo/Redo” mechanism.

1. The Command Interface

First, we define a common interface. Every action must know how to execute and, crucially, how to reverse itself.

public interface Command {
    void execute();
    void undo();
}

2. The Concrete Command (The “Action”)

Imagine a simple Document class that holds text. A WriteCommand would look like this:

public class WriteCommand implements Command {
    private Document doc;
    private String textAdded;

   public WriteCommand(Document doc, String textAdded) {
        this.doc = doc;
        this.textAdded = textAdded;
    }
    @Override
    public void execute() {
        doc.appendText(textAdded);
    }
    @Override
    public void undo() {
        doc.removeLastChars(textAdded.length());
    }
}

3. The Invoker (The Manager)

This is the “Brain” that manages the stacks. It doesn’t need to know what the commands do, only that they can be pushed, popped, and executed.

import java.util.Stack;

public class EditorInvoker {
    private Stack<Command> undoStack = new Stack<>();
    private Stack<Command> redoStack = new Stack<>();
    public void executeCommand(Command cmd) {
        cmd.execute();
        undoStack.push(cmd);
        redoStack.clear(); // New actions usually clear the redo history
    }
    public void undo() {
        if (!undoStack.isEmpty()) {
            Command cmd = undoStack.pop();
            cmd.undo();
            redoStack.push(cmd);
        }
    }
    public void redo() {
        if (!redoStack.isEmpty()) {
            Command cmd = redoStack.pop();
            cmd.execute();
            undoStack.push(cmd);
        }
    }
}

4. The Receiver: Document

This class contains the actual “state” and the logic for manipulating that state.

public class Document {
    private StringBuilder content = new StringBuilder();

   public void appendText(String text) {
        content.append(text);
        System.out.println("Current Doc: " + content.toString());
    }
    public void removeLastChars(int count) {
        int len = content.length();
        if (count <= len) {
            content.delete(len - count, len);
        }
        System.out.println("Current Doc: " + content.toString());
    }
    public String getContent() {
        return content.toString();
    }
}

5. Client

public class Main {
    public static void main(String[] args) {
        // 1. Create the Receiver
        Document myDoc = new Document();

        // 2. Create the Invoker
        EditorInvoker editor = new EditorInvoker();

        // 3. Client creates Concrete Commands and associates them with the Receiver
        Command step1 = new WriteCommand(myDoc, "Hello ");
        Command step2 = new WriteCommand(myDoc, "World!");

        // 4. Client tells Invoker to execute
        System.out.println("--- Executing ---");
        editor.executeCommand(step1);
        editor.executeCommand(step2);

        // 5. Test Undo/Redo
        System.out.println("--- Undoing ---");
        editor.undo(); // Removes "World!"

        System.out.println("--- Redoing ---");
        editor.redo(); // Puts "World!" back
    }

메타데이터
post_id
7cd99e4e2eb8
slug
command-design-pattern-7cd99e4e2eb8
url
https://medium.com/@kandaanusha/command-design-pattern-7cd99e4e2eb8
canonical_url
https://medium.com/@kandaanusha/command-design-pattern-7cd99e4e2eb8
author_url
https://medium.com/@kandaanusha
status
ok
fetched_at
2026-08-16 14:54:38