Java 3 min read

The Command Design Pattern: Turning Actions into Objects

Master the Command Pattern in Java. Learn how to encapsulate requests as objects to enable Undo/Redo, queuing, and macro commands.

MR

Moshiour Rahman

Advertisement

The Problem: Hardcoded Buttons

Imagine you are building a Universal Remote Control. It has 4 buttons. If you code it like this:

class Remote {
    private Light light;
    private TV tv;

    public void pressButton1() {
        light.on(); // Hardcoded!
    }
    
    public void pressButton2() {
        tv.volumeUp(); // Hardcoded!
    }
}

This is rigid. You can’t change what Button 1 does at runtime. You can’t “record” a macro of clicks. You can’t “Undo”.

The Solution: The Command Pattern

The Command Pattern turns a request into a stand-alone object. This lets you parameterize methods with different requests, delay or queue a request’s execution, and support undoable operations.

Real-Life Analogy: Ordering at a Diner 🍔

  1. You (Client): Give an order (“Burger, no onions”) to…
  2. The Waiter (Invoker): Takes the order, writes it on a ticket (Command Object).
  3. The Cook (Receiver): Reads the ticket and cooks the burger.

The waiter doesn’t need to know how to cook a burger. They just hold the Command (Ticket) and pass it to the receiver.

Visualizing the Pattern

Command Pattern

Implementation

1. The Command Interface

public interface Command {
    void execute();
    void undo(); // Critical for Undo features
}

2. The Receiver (The Hardware)

public class Light {
    public void on() { System.out.println("Light ON"); }
    public void off() { System.out.println("Light OFF"); }
}

3. Concrete Commands

public class LightOnCommand implements Command {
    private Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.on();
    }

    @Override
    public void undo() {
        light.off(); // Simple undo logic
    }
}

4. The Invoker (The Remote)

public class RemoteControl {
    private Command slot;

    public void setCommand(Command command) {
        this.slot = command;
    }

    public void pressButton() {
        slot.execute();
    }
    
    public void pressUndo() {
        slot.undo();
    }
}

Usage

RemoteControl remote = new RemoteControl();
Light livingRoomLight = new Light();

// Create the 'ticket'
Command lightOn = new LightOnCommand(livingRoomLight);

// Load the remote
remote.setCommand(lightOn);

// Press button
remote.pressButton(); // Output: Light ON

// Oops, didn't mean to
remote.pressUndo();   // Output: Light OFF

In The Wild (Real World Examples)

1. java.lang.Runnable

One of the interface definitions of Command is simply void execute(). Does that look familiar? Runnable is effectively a Command interface. Thread pools execute Runnables.

2. GUI Actions (Swing Action / JavaFX)

Text Editors use Command pattern heavily for Check/Undo operations on Ctrl+Z.

Cheat Sheet

FeatureDetails
CategoryBehavioral
Problem SolvedNeed for Undo/Redo, Job Queues, Macros
Key implementationexecute() method in an interface
ProsDecoupling (Invoker doesn’t know Receiver), Undo/Redo support
ConsLots of tiny classes for every single action

Tips to Remember 🧠

  • “The Ticket”: Think of the diner order ticket. It’s an object representing an action.
  • “Undo”: If you need Undo/Redo, you almost certainly need Command. You typically keep a Stack<Command> history.

Advertisement

MR

Moshiour Rahman

Software Architect & AI Engineer

Share:
MR

Moshiour Rahman

Software Architect & AI Engineer

Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.

Related Articles

Comments

Comments are powered by GitHub Discussions.

Configure Giscus at giscus.app to enable comments.