Definition: Encapsulate a request into an object, allowing you to parameterize the client using different requests, queue requests or record request logs, and provide command revocation and recovery functions.
Type: Behavioral Pattern
Class diagram:
The structure of command mode
As the name suggests, command mode is the encapsulation of commands. First, let’s take a look at the basic structure in the command mode class diagram:
Command class: is an abstract class that declares the commands that need to be executed. Generally speaking, an execute method must be published to the public to execute the command.
ConcreteCommand class: The implementation class of the Command class, implements the methods declared in the abstract class.
Client class: The final client calling class.
The functions of the above three classes should be easier to understand. Let’s focus on the Invoker class and Recevier class.
Invoker class: The caller is responsible for invoking commands.
Receiver class: The receiver is responsible for receiving and executing commands.
To put it bluntly, the so-called encapsulation of commands is nothing more than writing a series of operations into a method and then being called by the client. It is reflected on the class diagram. It only takes a ConcreteCommand class and Client class to complete the encapsulation of commands. Even if it goes further, in order to increase flexibility, a Command class can be added for appropriate abstraction. What is the function of this caller and receiver?
In fact, you can think from another perspective: if you simply encapsulate some operations as a command for others to call, how can it be called a pattern? As a behavioral model, the command mode must first achieve low coupling. Only when the coupling degree is low can flexibility be improved. The purpose of adding the caller and receiver roles is precisely for this.
example:
The simulation of the operation of the TV includes power-on, shutdown, and change-in commands. The code is as follows
//Interface for executing command public interface Command { void execute(); } //Command receiver Receiver public class Tv { public int currentChannel = 0; public void turnOn() { System.out.println("The televisino is on."); } public void turnOff() { System.out.println("The television is off."); } public void changeChannel(int channel) { this.currentChannel = channel; System.out.println("Now TV channel is " + channel); } } //Shut down command ConcreteCommand public class CommandOn implements Command { private Tv myTv; public CommandOn(Tv tv) { myTv = tv; } public void execute() { myTv.turnOn(); } } //Shut down command ConcreteCommand public class CommandOff implements Command { private Tv myTv; public CommandOff(Tv tv) { myTv = tv; } public void execute() { myTv.turnOff(); } } //Channel switching command ConcreteCommand public class CommandChange implements Command { private Tv myTv; private int channel; public CommandChange(Tv tv, int channel) { myTv = tv; this.channel = channel; } public void execute() { myTv.changeChannel(channel); } } //It can be regarded as a remote control Invoker public class Control { private Command onCommand, offCommand, changeChannel; public Control(Command on, Command off, Command channel) { onCommand = on; offCommand = off; changeChannel = channel; } public void turnOn() { onCommand.execute(); } public void turnOff() { offCommand.execute(); } public void changeChannel() { changeChannel.execute(); } } //Test class Client public class Client { public static void main(String[] args) { // Command recipient Receiver Tv myTv = new Tv(); // Power-on command ConcreteCommond CommandOn on = new CommandOn(myTv); // Shutdown command ConcreteCommond CommandOff off = new CommandOff(myTv); // Channel switching command ConcreteCommond CommandChange channel = new CommandChange(myTv, 2); // Command control object Invoker Control control = new Control(on, off, channel); // Power-on control.turnOn(); // Switch channel control.changeChannel(); // shut down control.turnOff(); } }Execution results
The televisino is on. Now TV channel is 2 The television is off.
Advantages and disadvantages of command mode
First of all, the command mode is very encapsulation: each command is encapsulated, and for the client, the corresponding command is called as much as the function is needed without knowing how the command is executed. For example, there is a set of file operation commands: create a new file, copy a file, and delete a file. If these three operations are encapsulated into a command class, the client only needs to know that there are these three command classes. As for the logic encapsulated in the command class, the client does not need to know.
Secondly, the command mode has a good scalability. In the command mode, the most basic encapsulation of operations in the receiver class, and the command class secondary encapsulation of these basic operations. When adding new commands, the writing of the command class is generally not from scratch. There are a large number of receiver classes for call, and there are also a large number of command classes for call, and the code is very reusable. For example, in the operation of a file, we need to add a command to cut a file, and we only need to combine the two commands of copying a file and deleting a file, which is very convenient.
Finally, let’s talk about the disadvantages of the command mode, that is, if there are many commands, it will be a headache to develop. Especially many simple commands are only a few lines of code to implement. If you use the command mode, you don’t have to worry about how simple the command is, you need to write a command class to encapsulate it.
Applicable scenarios for command mode
For most request-response mode functions, it is more suitable to use the command mode. As the command mode definition says, the command mode is more convenient for implementing functions such as logging and undoing operations.
Summarize
Whether to use the mode in an occasion is a very tangled question for all developers. Sometimes, because of the foreseeing some changes in requirements, a certain design pattern is used for the flexibility and scalability of the system, but this foreseeable requirement does not. On the contrary, many unforeseeable requirements have come, resulting in the design pattern used playing the opposite role when modifying the code, so that the entire project team complained. I believe every programmer has encountered such an example. Therefore, based on the principle of agile development, when we design programs, if we can solve them well without using a certain pattern according to the current needs, then we should not introduce it, because it is not difficult to introduce a design pattern. We can do it on the system when we really need it to use it and introduce this design pattern.
Take command mode as an example. In our development, the request-response mode function is very common. Generally speaking, we will encapsulate the response operation to the request into a method. This encapsulated method can be called a command, but not a command mode. Whether this design should be raised to the height of the pattern needs to be considered separately, because if the command mode is used, the two roles of caller and receiver must be introduced. The logic originally placed in one place is scattered into three categories. When designing, it is necessary to consider whether this cost is worth it.