How to use the Command pattern in Java

One of our biggest challenges as software developers is organizing our code so that it is easier to extend and maintain. The Command pattern helps us do that by encapsulating all the data required to perform an action into a single Command object.

You might recognize the Command pattern because we use it all the time in our everyday lives. A good example is using a remote control device to turn on a television, switch channels, turn up the volume, and so on. Every one of these actions is encapsulated in the remote control device.

Something else to note about all of these actions is that they are reversible: you can turn on the TV, and you can also turn it off. Additionally, some of the actions must be done in order: you must turn on the TV before you can turn up the volume.

In this Java code challenge, you’ll learn about the Command design pattern and see several examples of the pattern in practice. I will also discuss how the Command pattern implements two core principles of the SOLID model. The two principles are the single-responsibility principle, which states that a class should have only one job, and the open-closed principle, which states that objects or entities should be open for extension but closed for modification.

What is the Command pattern?

The Command pattern is one of the 23 design patterns introduced with the Gang of Four design patterns. Command is a behavioral design pattern, meaning that it aims to execute an action in a specific code pattern.

When it was first introduced, the Command pattern was sometimes explained as callbacks for Java. While it started out as an object-oriented design pattern, Java 8 introduced lambda expressions, allowing for an object-functional implementation of the Command pattern. This article includes an example using a lambda expression in the Command pattern.

As with all design patterns, it’s very important to know when to apply the Command pattern, and when another pattern might be better. Using the wrong design pattern for a use case can make your code more complicated, not less.

The Command pattern in the JDK

We can find many examples of the Command pattern in the Java Development Kit, and in the Java ecosystem. One popular example is using the Runnable functional interface with the Thread class. Another is handling events with an ActionListener. Let’s explore both of these examples.

The Command pattern with Thread and Runnable

Runnable is an interface that includes the run() method. The following code snippet shows the run() method’s signature. As you can see, it is possible to pass a command in the run() method:


@FunctionalInterface
public interface Runnable { public abstract void run();
}

Thread is the most-used class that receives a Runnable. Let’s see how we can pass a command to the Thread class:


Runnable command = () -> System.out.println("Executing command!");
Thread thread = new Thread(command); // Setting command
thread.start(); 

In this code, we implement the command behavior in the run() method with a lambda expression. Instead of the lambda, we could use an anonymous inner class, which is an unnamed class that implements Runnable and the run() method. But that approach would make the code more verbose. Using the lambda is more concise and easier to read.

We then pass the command to the Thread class. Finally, we execute the command by invoking the start() method.

Here’s the output we can expect from this code:


Executing command!

The Command pattern with ActionListener

Another good example in the JDK is the ActionListener interface. I know it’s an older interface, but it’s suitable as an example.

In the following code, we create a JFrame and a JButton. We then set the action in the button by invoking the addActionListener() method. In this case, we’ll just change the text from “Click me” to “Clicked.” Then, we’ll add the button to the frame, and show the frame with the button:


JFrame frame = new JFrame(); JButton button = new JButton("Click Me");
button.addActionListener(e -> button.setText("Clicked!")); // Command implementation frame.add(button);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true); 

Figure 1 shows the results of this code after the button is clicked.

Command pattern with ActionListener. IDG

Figure 1. ActionListener in action.

Drive my motorcycle! The Command pattern in a Vehicle interface

Now that you’ve seen examples of the Command pattern in the JDK, let’s create our own. First, take a look at the class diagram in Figure 2.

Command pattern for a Vehicle interface. IDG

Figure 2. A diagram of the Command pattern for a Vehicle interface.

There are three parts to the diagram, which I’ll explain.

Command

The foundation class for the Command pattern is the Command interface. We use this interface anytime we want to execute or revert a command:


public interface Command { void execute(); void revert(); }

Receiver

Next, we need to create the class that has the behavior to execute the command. We start with the Vehicle interface, then create the Motorcycle and Truck classes to implement it:


public interface Vehicle { void start(); void stop(); void accelerate(); } public class Motorcycle implements Vehicle { @Override public void start() { System.out.println("Starting motorcycle..."); } @Override public void stop() { System.out.println("Stopping motorcycle..."); } @Override public void accelerate() { System.out.println("Accelerating motorcycle..."); } } public class Truck implements Vehicle { @Override public void start() { System.out.println("Starting truck..."); } @Override public void stop() { System.out.println("Stopping truck..."); } @Override public void accelerate() { System.out.println("Accelerating truck..."); } @Override public void decelerate() { System.out.println("Decelerating truck..."); } }

Also notice that the Vehicle interface makes the code more flexible and easier to change: we could easily add another vehicle such as Car that implements the Vehicle interface. This part of the Command pattern is a great example of the open-closed SOLID principle. (Remember that this principle states that objects or entities should be extensible.)

Invoker

Now, we have the Motorcycle and Truck behavior but we need a class to execute it. In our case, this class will be the GhostRider. GhostRider will drive the Motorcycle and Truck classes.

GhostRider receives the command in the constructor and invokes the execute() method from the command into the takeAction() and revertAction() methods:


public class GhostRider { Command command; public GhostRider(Command command){ this.command = command; } public void setCommand(Command command) { this.command = command; } public void takeAction(){ command.execute(); } public void revertAction() { command.revert(); }
}

Implementing commands in the Command pattern

Now, let’s create the StartMotorcycle, AccelerateMotorcycle, and StartAllVehicles commands. Each command implements the Command interface and receives Vehicle in the constructor. Then, it invokes the method that corresponds to each command class from Vehicle into the execute() method:


public class StartMotorcycle implements Command { Vehicle vehicle; public StartMotorcycle(Vehicle vehicle) { this.vehicle = vehicle; } public void execute() { vehicle.start(); } @Override public void revert() { vehicle.stop(); } } public class AccelerateMotorcycle implements Command { Vehicle vehicle; public AccelerateMotorcycle(Vehicle vehicle){ this.vehicle = vehicle; } public void execute() { vehicle.accelerate(); } @Override public void revert() { vehicle.decelerate(); } } import java.util.List; public class StartAllVehicles implements Command { List<Vehicle> vehicles; public StartAllVehicles(List<Vehicle> vehicles) { this.vehicles = vehicles; } public void execute() { vehicles.forEach(vehicle -> vehicle.start()); } @Override public void revert() { vehicles.forEach(vehicle -> vehicle.stop()); } }

Run the commands

It’s time to run our commands! For this, we first instantiate the Motorcycle class that has the Command behavior, then pass it into each Command implementation.

Notice that we are also using the StartAllVehicles command to start (and stop) multiple vehicles at once.

Then, we instantiate the GhostRider class that will execute each command. Finally, we invoke the takeAction() and revertAction() methods:


public class RideVehicle { public static void main(String[] args) { Vehicle motorcycle = new Motorcycle(); StartMotorcycle startCommand = new StartMotorcycle(motorcycle); GhostRider ghostRider = new GhostRider(startCommand); ghostRider.takeAction(); AccelerateMotorcycle accelerateCommand = new AccelerateMotorcycle(motorcycle); ghostRider.setCommand(accelerateCommand); ghostRider.takeAction(); ghostRider.revertAction(); Vehicle truck = new Truck(); List<Vehicle> vehicles = List.of(motorcycle, truck); StartAllVehicles startAllVehicles = new StartAllVehicles(vehicles); startAllVehicles.execute(); startAllVehicles.revert(); } }

Here is the output from this code:


Starting motorcycle...
Accelerating motorcycle...
Decelerating motorcycle...
Starting motorcycle...
Starting truck...
Stopping motorcycle...
Stopping truck…

When to use the Command pattern

A crucial rule for design patterns is to know when to use them. No matter how great a pattern is, implementing it for the wrong use case will make your code much worse. Here are some guidelines for using the Command pattern:

  1. You have multiple commands that should be implemented separately based on the SOLID principles of single-responsibility and open-closed design.
  2. You need to create reversible commands, such as adding and removing an item from a shopping cart.
  3. You need to be able to create logs whenever a command is executed. Each command in the Command pattern is encapsulated, so creating logs is easy.
  4. You need to be able to execute multiple commands at once. You can easily add a Queue, List, or Set into a command’s implementation and execute them.

What to remember about the Command pattern

To summarize, remember the following about the Command pattern:

  • It applies the SOLID principles of single-responsibility and open-closed design.
  • It encapsulates and decouples the behavior of commands, which makes your code more extensible.
  • It’s used in the JDK with the Thread class and Runnable and ActionListener interfaces.
  • It encapsulates the behavior of commands within a single Command implementation.
  • It lets you execute and revert single commands.
  • It lets you execute and revert multiple commands together.