Learn how to use the Command pattern to encapsulate requests as objects, which you can execute alone or in sequence in your Java programs. Credit: Miku 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. 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. 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: You have multiple commands that should be implemented separately based on the SOLID principles of single-responsibility and open-closed design. You need to create reversible commands, such as adding and removing an item from a shopping cart. 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. 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. Related content feature 14 great preprocessors for developers who love to code Sometimes it seems like the rules of programming are designed to make coding a chore. Here are 14 ways preprocessors can help make software development fun again. By Peter Wayner Nov 18, 2024 10 mins Development Tools Software Development feature Designing the APIs that accidentally power businesses Well-designed APIs, even those often-neglected internal APIs, make developers more productive and businesses more agile. By Jean Yang Nov 18, 2024 6 mins APIs Software Development news Spin 3.0 supports polyglot development using Wasm components Fermyon’s open source framework for building server-side WebAssembly apps allows developers to compose apps from components created with different languages. By Paul Krill Nov 18, 2024 2 mins Microservices Serverless Computing Development Libraries and Frameworks news Go language evolving for future hardware, AI workloads The Go team is working to adapt Go to large multicore systems, the latest hardware instructions, and the needs of developers of large-scale AI systems. By Paul Krill Nov 15, 2024 3 mins Google Go Generative AI Programming Languages Resources Videos