Command Design Pattern in Java

This article explains Command design pattern in java with UML class diagram. It then takes an example scenario in java and explains it with class diagram and code.
Introduction Command Design Pattern is a behavioral design pattern among the Gang Of Four(GOF) Design PatternsClick to read: Gang Of Four(GOF) Design Patterns. Being a behavioral design pattern, the Command pattern deals with how objects interact - here, by turning a request into an object of its own. What is Command Design Pattern The Command design pattern encapsulates a request as an object. Instead of one object calling a method on another directly, the call - which object to act on, which action, and with which parameters - is wrapped in a command object with a common execute() method. The object which triggers the request, the invoker, then only needs to know about the command interface, not about the object which does the work, the receiver. Because requests are now objects, they can be stored, passed around, queued, logged, and undone. Scenarios in which Command Design Pattern can be used
  1. Decoupling the sender of a request from its receiver: When objects such as buttons, menu items or remote control slots should trigger actions without knowing which object performs them - so the same invoker can be configured with any action.
  2. Undo and redo: When operations must be reversible. Each command stores what it needs to reverse itself, and a history of executed commands supports undo.
  3. Queuing, scheduling and logging requests: When requests should run later, on another thread, or be recorded so they can be replayed after a crash - as in job queues and transaction logs.
Class Diagram for Command Design Pattern
Command Design Pattern Class Diagram
Explanation of Command Design Pattern's Class Diagram
  • Command is the interface for executing an operation, with a single execute() method.
  • ConcreteCommand binds a Receiver to an action. Its execute() calls the corresponding method on the receiver, and it can store state needed to undo the action.
  • Receiver knows how to actually perform the work.
  • Invoker holds commands and asks them to execute, without knowing anything about receivers.
  • Client creates the receiver and the concrete commands, and gives the commands to the invoker.
Command Design Pattern in Java - Class Diagram
Command Design Pattern in Java Class Diagram
The example is a smart home remote control. Pressing a button executes a command; the remote keeps a history of the commands it has executed, so the last action can be undone.
Code for the classes shown in Java Example's Class Diagram
Command.java - the command interface
//Command.java
public interface Command {
 void execute();
 void undo();
}
Light.java - the receiver
//Light.java
public class Light {
 private final String room;
 private boolean on;

 public Light(String room) { this.room = room; }

 public void switchOn() { on = true; System.out.println("  " + room + " light is ON"); }
 public void switchOff() { on = false; System.out.println("  " + room + " light is OFF"); }
 public boolean isOn() { return on; }
}
LightOnCommand.java and LightOffCommand.java - the concrete commands
//LightOnCommand.java
class LightOnCommand implements Command {
 private final Light light;
 LightOnCommand(Light light) { this.light = light; }
 public void execute() { light.switchOn(); }
 public void undo() { light.switchOff(); }
}
//LightOffCommand.java
class LightOffCommand implements Command {
 private final Light light;
 LightOffCommand(Light light) { this.light = light; }
 public void execute() { light.switchOff(); }
 public void undo() { light.switchOn(); }
}
RemoteControl.java - the invoker
//RemoteControl.java
import java.util.ArrayDeque;
import java.util.Deque;

public class RemoteControl {
 private final Deque<Command> history = new ArrayDeque<>();

 public void press(Command command) {
  command.execute();
  history.push(command);                  // remember it for undo
 }

 public void undoLast() {
  if (history.isEmpty()) {
   System.out.println("  Nothing to undo");
   return;
  }
  history.pop().undo();
 }
}
HomeAutomationApp.java (with the main() method)
//HomeAutomationApp.java
public class HomeAutomationApp {
 public static void main(String[] args) {
  Light kitchen = new Light("Kitchen");
  Light bedroom = new Light("Bedroom");
  RemoteControl remote = new RemoteControl();

  System.out.println("Pressing buttons:");
  remote.press(new LightOnCommand(kitchen));
  remote.press(new LightOnCommand(bedroom));
  remote.press(new LightOffCommand(kitchen));

  System.out.println("Undoing the last two actions:");
  remote.undoLast();                      // kitchen back ON
  remote.undoLast();                      // bedroom back OFF

  System.out.println("An ad-hoc command, then three undos:");
  remote.press(new Command() {            // ad-hoc command without a named class
   public void execute() { System.out.println("  Playing music"); }
   public void undo() { System.out.println("  Music stopped"); }
  });
  remote.undoLast();
  remote.undoLast();
  remote.undoLast();
  System.out.println("Kitchen on? " + kitchen.isOn() + ", bedroom on? " + bedroom.isOn());
 }
}
 OUTPUT on running HomeAutomationApp.java
Pressing buttons:
  Kitchen light is ON
  Bedroom light is ON
  Kitchen light is OFF
Undoing the last two actions:
  Kitchen light is ON
  Bedroom light is OFF
An ad-hoc command, then three undos:
  Playing music
  Music stopped
  Kitchen light is OFF
  Nothing to undo
Kitchen on? false, bedroom on? false
Explanation of Java Example's Class Diagram & Code
  • Command is the command interface, extended with undo() so that commands can reverse themselves.
  • LightOnCommand and LightOffCommand are concrete commands. Each holds the Light it acts on - the receiver - and knows which method to call to execute and to undo.
  • RemoteControl is the invoker. It executes any Command it is given and pushes it onto a history stack; undoLast() pops the most recent command and undoes it. It knows nothing about lights - the same remote could control a fan or a music player.
  • HomeAutomationApp is the client. It creates the receivers and commands and hands the commands to the remote. The undo calls reverse the actions in the opposite order they were done, and a further undo on an empty history is handled safely.
  • The anonymous class shows that commands do not always need a named class. A command with only execute() is just a Runnable, so it can be written as a lambdaClick to read: lambda: Runnable command = () -> light.switchOn();.
Note - The Command pattern is everywhere in Java: Runnable and Callable objects submitted to an ExecutorService are commands, the executor is the invoker, and Swing's Action objects attach the same command to a menu item, a toolbar button and a keyboard shortcut.
Summary In the above tutorial we understood what is Command design pattern and the main scenarios in which it is applicable. We then looked at the UML class diagram for Command Design Pattern & its explanation, a Java use case implementing a smart home remote control with undo, with its class diagram, code and output, followed by an explanation of both the class diagram & code. This concludes the tutorial on Command design pattern.