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 What is Rust? Safe, fast, and easy software development Unlike most programming languages, Rust doesn't make you choose between speed, safety, and ease of use. Find out how Rust delivers better code with fewer compromises, and a few downsides to consider before learning Rust. By Serdar Yegulalp Nov 20, 2024 11 mins Rust Programming Languages Software Development how-to Kotlin for Java developers: Classes and coroutines Kotlin was designed to bring more flexibility and flow to programming in the JVM. Here's an in-depth look at how Kotlin makes working with classes and objects easier and introduces coroutines to modernize concurrency. By Matthew Tyson Nov 20, 2024 9 mins Java Kotlin Programming Languages analysis Azure AI Foundry tools for changes in AI applications Microsoft’s launch of Azure AI Foundry at Ignite 2024 signals a welcome shift from chatbots to agents and to using AI for business process automation. By Simon Bisson Nov 20, 2024 7 mins Microsoft Azure Generative AI Development Tools news Microsoft unveils imaging APIs for Windows Copilot Runtime Generative AI-backed APIs will allow developers to build image super resolution, image segmentation, object erase, and OCR capabilities into Windows applications. By Paul Krill Nov 19, 2024 2 mins Generative AI APIs Development Libraries and Frameworks Resources Videos