Behavioral Design Pattern · Java

Command Design Pattern in Java

Encapsulate a request as an object so it can be executed, queued, logged, or undone.

What is Command?

The Command pattern turns a request into a separate object. The sender, such as a remote control, only knows how to execute a command. It does not need to know how the receiver, such as a television, performs the operation. This decoupling makes commands easier to add, reuse, queue, test, and undo.

Beginner-friendly Java example

Focus on the roles in the example first. The pattern becomes easier when you can identify the sender, receiver, context, state, or strategy involved.

// Step 1: Define the Command interface
interface Command {
    void execute();
}

// Step 2: Implement concrete commands
class TurnOnCommand implements Command {
    private ElectronicDevice device;

    public TurnOnCommand(ElectronicDevice device) {
        this.device = device;
    }

    @Override
    public void execute() {
        device.turnOn();
    }
}

class TurnOffCommand implements Command {
    private ElectronicDevice device;

    public TurnOffCommand(ElectronicDevice device) {
        this.device = device;
    }

    @Override
    public void execute() {
        device.turnOff();
    }
}

// Step 3: Define the Receiver
class ElectronicDevice {
    private String name;

    public ElectronicDevice(String name) {
        this.name = name;
    }

    public void turnOn() {
        System.out.println(name + " is turned on.");
    }

    public void turnOff() {
        System.out.println(name + " is turned off.");
    }
}

// Step 4: Create the Invoker
class RemoteControl {
    private Command command;

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

    public void pressButton() {
        command.execute();
    }
}

// Step 5: Test the implementation
public class Main {
    public static void main(String[] args) {
        ElectronicDevice tv = new ElectronicDevice("TV");
        Command turnOnCommand = new TurnOnCommand(tv);
        Command turnOffCommand = new TurnOffCommand(tv);

        RemoteControl remoteControl = new RemoteControl();

        remoteControl.setCommand(turnOnCommand);
        remoteControl.pressButton();

        remoteControl.setCommand(turnOffCommand);
        remoteControl.pressButton();
    }
}

Benefits and trade-offs

Benefits
  • Keeps responsibilities focused.
  • Reduces conditional and tightly coupled code.
  • Makes behavior easier to extend and test.
Trade-offs
  • Can introduce extra objects and interfaces.
  • Too many small classes can make simple logic harder to follow.

Real-time use cases

  • Remote-control buttons
  • Undo and redo actions
  • Job and message queues
  • GUI buttons and menus
  • Audit logging and retry workflows
Key takeawayEncapsulate a request as an object so it can be executed, queued, logged, or undone. Use it when behavior or communication is changing faster than the objects themselves.