Command Design Pattern in Java

1. Definition

The Command Design Pattern encapsulates a request as an object, thereby allowing users to parameterize clients with different requests, queue requests, and support undoable operations. It decouples the sender (Invoker) from the receiver (Receiver) by wrapping the request as an object (Command).

2. Problem Statement

Consider a scenario where you have a remote control for various devices. How can you design the remote control in such a way that adding new commands (like light on/off, fan on/off) doesn't require modifying the existing remote control code?

3. Solution

The Command pattern offers a solution by encapsulating each operation in a command object, decoupling the object that invokes the operation from the object that performs it. The invoker only knows about the command interface, while concrete command classes implement the execution.

4. Real-World Use Cases

1. GUI buttons and menu items in software applications.

2. Macro recording in software applications.

3. Multi-level undo and redo in software editors.

5. Implementation Steps

1. Define a command interface with an execute method.

2. Create one or more derived classes that encapsulate a request from the receiver.

3. Define classes that use the command objects.

4. A client controls the command execution.

6. Implementation

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

// Step 2: Receiver Class
class Light {
    public void on() {
        System.out.println("Light is ON");
    }

    public void off() {
        System.out.println("Light is OFF");
    }
}

// Step 3: ConcreteCommand Classes
class LightOnCommand implements Command {
    private Light light;

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

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

class LightOffCommand implements Command {
    private Light light;

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

    public void execute() {
        light.off();
    }
}

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

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

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

// Client
public class CommandPatternDemo {
    public static void main(String[] args) {
        Light light = new Light();
        RemoteControl control = new RemoteControl();

        // Switch on the light
        control.setCommand(new LightOnCommand(light));
        control.pressButton();

        // Switch off the light
        control.setCommand(new LightOffCommand(light));
        control.pressButton();
    }
}

Output:

Light is ON
Light is OFF

Explanation

In the provided example, Light acts as the receiver that performs the real action. The LightOnCommand and LightOffCommand classes encapsulate the commands. The RemoteControl acts as the invoker, while the client sets the command it wants to execute.

7. When to use?

Use the Command Pattern when:

1. You need to parameterize objects with operations.

2. You want to queue operations, schedule their execution, or execute them remotely.

3. You require support for undoable actions.


Comments