1. The Problem: Tight Coupling of Senders and Receivers
Imagine a Remote Control that can turn on a Light, open a Garage, or play a Radio.
- If the Remote class has hardcoded logic for
light.turnOn(),garage.open(), etc., it becomes massive and hard to maintain.
2. The Solution: Command Pattern
We wrap the action into a Command object. The Remote just knows it needs to call command.execute().
Step 1: The Command Interface
public interface Command {
void execute();
void undo();
}
Step 2: Concrete Commands
public class LightOnCommand implements Command {
private Light light;
public void execute() { light.on(); }
public void undo() { light.off(); }
}
Step 3: The Invoker (Remote)
public class RemoteControl {
private Command slot;
public void setCommand(Command c) { this.slot = c; }
public void pressButton() { slot.execute(); }
}
3. Real-world Intuition: The Restaurant Order
You (The Client) tell the Waiter (The Invoker) what you want. The Waiter writes it on a piece of paper (The Command). The Chef (The Receiver) cooks the food. The Waiter doesn't need to know how to cook; they just pass the "Command" paper to the kitchen.
4. Why use it?
- Undo/Redo: Keep a stack of executed commands. To undo, just call
pop().undo(). - Macro Commands: Combine multiple commands into one (e.g., "Party Mode" turns on lights, plays music, and dims blinds).
- Queuing: Commands can be stored in a queue and processed by workers later.
Final Takeaway
Use the Command pattern whenever you need to parameterize objects with actions or support reversible operations.