Certainly one of our largest challenges as software program builders is organizing our code in order that it’s simpler to increase and preserve. The Command sample helps us try this by encapsulating all the info required to carry out an motion right into a single Command
object.
You would possibly acknowledge the Command sample as a result of we use it on a regular basis in our on a regular basis lives. instance is utilizing a distant management system to activate a tv, change channels, flip up the quantity, and so forth. Each one in all these actions is encapsulated within the distant management system.
One thing else to notice about all of those actions is that they’re reversible: you possibly can activate the TV, and you may also flip it off. Moreover, a number of the actions should be achieved so as: it’s essential to activate the TV earlier than you possibly can flip up the quantity.
On this Java code problem, you will study concerning the Command design sample and see a number of examples of the sample in observe. I may even talk about how the Command sample implements two core ideas of the SOLID mannequin. The 2 ideas are the single-responsibility precept, which states {that a} class ought to have just one job, and the open-closed precept, which states that objects or entities must be open for extension however closed for modification.
What’s the Command sample?
The Command sample is without doubt one of the 23 design patterns launched with the Gang of 4 design patterns. Command is a behavioral design sample, that means that it goals to execute an motion in a particular code sample.
When it was first launched, the Command sample was generally defined as callbacks for Java. Whereas it began out as an object-oriented design sample, Java 8 launched lambda expressions, permitting for an object-functional implementation of the Command sample. This text consists of an instance utilizing a lambda expression within the Command sample.
As with all design patterns, it is crucial to know when to use the Command sample, and when one other sample could be higher. Utilizing the fallacious design sample for a use case could make your code extra sophisticated, not much less.
The Command sample within the JDK
We are able to discover many examples of the Command sample within the Java Improvement Equipment, and within the Java ecosystem. One in style instance is utilizing the Runnable
purposeful interface with the Thread
class. One other is dealing with occasions with an ActionListener
. Let’s discover each of those examples.
The Command sample with Thread and Runnable
Runnable
 is an interface that features the run()
technique. The next code snippet exhibits the run()
technique’s signature. As you possibly can see, it’s doable to move a command within the run()
technique:
@FunctionalInterface
public interface Runnable {
public summary void run();
}
Thread
is the most-used class that receives a Runnable
. Let’s examine how we are able to move a command to the Thread
class:
Runnable command = () -> System.out.println("Executing command!");
Thread thread = new Thread(command); // Setting command
thread.begin();
On this code, we implement the command habits within the run()
technique with a lambda expression. As a substitute of the lambda, we might use an nameless internal class, which is an unnamed class that implements Runnable
and the run()
technique. However that method would make the code extra verbose. Utilizing the lambda is extra concise and simpler to learn.
We then move the command to the Thread
class. Lastly, we execute the command by invoking the begin()
technique.
This is the output we are able to anticipate from this code:
Executing command!
The Command sample with ActionListener
One other good instance within the JDK is the ActionListener
interface. I do know it is an older interface, nevertheless it’s appropriate for example.
Within the following code, we create a JFrame
and a JButton
. We then set the motion within the button by invoking the addActionListener()
technique. On this case, we’ll simply change the textual content from “Click on me” to “Clicked.” Then, we’ll add the button to the body, and present the body with the button:
JFrame body = new JFrame();
JButton button = new JButton("Click on Me");
button.addActionListener(e -> button.setText("Clicked!")); // Command implementation
body.add(button);
body.pack();
body.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
body.setVisible(true);
Determine 1 exhibits the outcomes of this code after the button is clicked.
Drive my bike! The Command sample in a Car interface
Now that you have seen examples of the Command sample within the JDK, let’s create our personal. First, check out the category diagram in Determine 2.
There are three components to the diagram, which I will clarify.
Command
The inspiration class for the Command sample is the Command
interface. We use this interface anytime we wish to execute or revert a command:
public interface Command {
void execute();
void revert();
}
Receiver
Subsequent, we have to create the category that has the habits to execute the command. We begin with the Car
interface, then create the Bike
and Truck
lessons to implement it:
public interface Car {
void begin();
void cease();
void speed up();
}
public class Bike implements Car {
@Override
public void begin() {
System.out.println("Beginning bike...");
}
@Override
public void cease() {
System.out.println("Stopping bike...");
}
@Override
public void speed up() {
System.out.println("Accelerating bike...");
}
}
public class Truck implements Car {
@Override
public void begin() {
System.out.println("Beginning truck...");
}
@Override
public void cease() {
System.out.println("Stopping truck...");
}
@Override
public void speed up() {
System.out.println("Accelerating truck...");
}
@Override
public void decelerate() {
System.out.println("Decelerating truck...");
}
}
Additionally discover that the Car
interface makes the code extra versatile and simpler to vary: we might simply add one other car similar to Automotive
that implements the Car
interface. This a part of the Command sample is a good instance of the open-closed SOLID precept. (Do not forget that this precept states that objects or entities must be extensible.)
Invoker
Now, now we have the Bike
and Truck
habits however we want a category to execute it. In our case, this class would be the GhostRider
. GhostRider
will drive the Bike
and Truck
lessons.
GhostRider
receives the command within the constructor and invokes the execute()
technique from the command into the takeAction()
and revertAction()
strategies:
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 instructions within the Command sample
Now, let’s create the StartMotorcycle
, AccelerateMotorcycle
, and StartAllVehicles
instructions. Every command implements the Command
interface and receives Car
within the constructor. Then, it invokes the tactic that corresponds to every command class from Car
into the execute()
technique:
public class StartMotorcycle implements Command {
Car car;
public StartMotorcycle(Car car) {
this.car = car;
}
public void execute() {
car.begin();
}
@Override
public void revert() {
car.cease();
}
}
public class AccelerateMotorcycle implements Command {
Car car;
public AccelerateMotorcycle(Car car){
this.car = car;
}
public void execute() {
car.speed up();
}
@Override
public void revert() {
car.decelerate();
}
}
import java.util.Record;
public class StartAllVehicles implements Command {
Record<Car> automobiles;
public StartAllVehicles(Record<Car> automobiles) {
this.automobiles = automobiles;
}
public void execute() {
automobiles.forEach(car -> car.begin());
}
@Override
public void revert() {
automobiles.forEach(car -> car.cease());
}
}
Run the instructions
It is time to run our instructions! For this, we first instantiate the Bike
class that has the Command
habits, then move it into every Command
implementation.
Discover that we’re additionally utilizing the StartAllVehicles
command to begin (and cease) a number of automobiles directly.
Then, we instantiate the GhostRider
class that may execute every command. Lastly, we invoke the takeAction()
and revertAction()
strategies:
public class RideVehicle {
public static void fundamental(String[] args) {
Car bike = new Bike();
StartMotorcycle startCommand = new StartMotorcycle(bike);
GhostRider ghostRider = new GhostRider(startCommand);
ghostRider.takeAction();
AccelerateMotorcycle accelerateCommand = new AccelerateMotorcycle(bike);
ghostRider.setCommand(accelerateCommand);
ghostRider.takeAction();
ghostRider.revertAction();
Car truck = new Truck();
Record<Car> automobiles = Record.of(bike, truck);
StartAllVehicles startAllVehicles = new StartAllVehicles(automobiles);
startAllVehicles.execute();
startAllVehicles.revert();
}
}
Right here is the output from this code:
Beginning bike...
Accelerating bike...
Decelerating bike...
Beginning bike...
Beginning truck...
Stopping bike...
Stopping truck…
When to make use of the Command sample
A vital rule for design patterns is to know when to make use of them. Regardless of how nice a sample is, implementing it for the fallacious use case will make your code a lot worse. Listed here are some pointers for utilizing the Command sample:
- You’ve a number of instructions that must be carried out individually primarily based on the SOLID ideas of single-responsibility and open-closed design.
- That you must create reversible instructions, similar to including and eradicating an merchandise from a purchasing cart.
- You want to have the ability to create logs each time a command is executed. Every command within the Command sample is encapsulated, so creating logs is simple.
- You want to have the ability to execute a number of instructions directly. You may simply add a
Queue
,Record
, orSet
right into a command’s implementation and execute them.
What to recollect concerning the Command sample
To summarize, keep in mind the next concerning the Command sample:
- It applies the SOLID ideas of single-responsibility and open-closed design.
- It encapsulates and decouples the habits of instructions, which makes your code extra extensible.
- It is used within the JDK with the
Thread
class andRunnable
andActionListener
interfaces. - It encapsulates the habits of instructions inside a single
Command
implementation. - It permits you to execute and revert single instructions.
- It permits you to execute and revert a number of instructions collectively.
Copyright © 2022 IDG Communications, Inc.