I. Introduction
The 23 design patterns are roughly divided into three main categories:
There are five (creation mode): factory method mode, abstract factory mode, single case mode, prototype mode, builder mode.
Seven (structural mode): adapter mode, decorator mode, agent mode, appearance mode, bridging mode, combination mode, share mode.
Eleven (behavioral) modes: strategy mode, template method mode, observer mode, iteration sub-mode, responsibility chain mode, command mode, memo mode, status mode, visitor mode, mediator mode, interpreter mode.
Behavioral types can also be divided by the relationship between classes:
A basic introduction to command mode:
- Command Pattern: In software design, we often need to send requests to certain objects, but we don't know who the recipient of the request is or what the requested operation is. We just need to specify the specific recipient of the request while the program is running. In this case, we can use command mode to design.
- Naming patterns allow the sender and receiver of a request to decouple from each other, making the call relationship between objects more flexible and decoupling
- In naming mode, a request is encapsulated as an object so that different parameters are used to represent different requests (that is, naming), and command mode supports revocable operations.
- Common sense: the general issues orders and the soldier executes them. There are several roles: general (issuer of command), soldier (specific executor of command), command (connection of general and soldier)
- Invoker is the caller (general), Receiver is the callee (soldier), MyCommand is the command, implements the Command interface, and holds the receiving object
2. Command Mode
1. Command mode schematic class diagram
Explanation of the schematic class diagram:
- Invoker is the caller role
- Command: is a command role, where all commands that need to be executed can be interfaces or abstract classes
- Receiver: Receiver role, knowing how to perform and execute a request-related operation
- ConcreteCommand: Bind a recipient object to an action, call the recipient's corresponding action, and execute
- Decoupling between Invoker and Receiver is implemented through ConcreteCommand.
In the implementation class of the command, the recipient object must be held
3. Specific requirements
1. Smart Life
We bought a set of smart appliances, including lighting, fans, refrigerators, washing machines, which we can control by simply installing apps on our mobile phones. These smart home appliances come from different manufacturers. We don't want to install an App for each kind of home appliances and control them separately. We hope that only one app can control all smart home appliances.
To achieve the need for an app to control all smart home appliances, each smart home power plant owner needs to provide a unified interface for app calls, so command mode can be considered.
Command mode decouples the Requestor of an Action from the Executor of an Action object. In the example, the requester of the action is the mobile app, and the executor of the action is an appliances product of each manufacturer
2. Command mode scheme
Idea Analysis-Class Diagram-Taking Operation of Light as an Example
Explain:
-
Since there are multiple on/off buttons on the remote control, an array is made in RemoteController
-
Extensibility is good. For example, to increase the switching on and off of the TV, just add TVReceiver, as well as TVOnCommand and TVOffCommand, and you can use them. As the caller, RemoteController does not need to be changed (it conforms to the on/off principle), TV related code is omitted
Specific implementation
//Command interface. Java public interface Command { //Execute Action/Action public void execute(); //Undo Action/Action public void undo(); } // LightReceiver.java public class LightReceiver { public void on() { System.out.println("The light is on.. "); } public void off() { System.out.println("The light is off... "); } } // LightOnCommand.java public class LightOnCommand implements Command { //Aggregate LightReceiver LightReceiver light; public LightOnCommand(LightReceiver light) { this.light = light; } //Which method execute() calls is determined by business logic: if you think what "execution" means, just tune the relevant method @Override public void execute() { //Call recipient's method light.on(); } @Override public void undo() { light.off(); } } // LightOffCommand.java public class LightOffCommand implements Command { //Aggregate LightReceiver LightReceiver light; public LightOffCommand(LightReceiver light) { this.light = light; } @Override public void execute() { light.off(); } @Override public void undo() { light.on(); } } // NoCommand.java //No command, empty execution: used to initialize each button, when an empty command is called, the object does nothing //In fact, this is also a design mode, which can eliminate empty judgments public class NoCommand implements Command { @Override public void execute() { } @Override public void undo() { } } // RemoteController.java public class RemoteController { //Array of commands for the Open button Command[] onCommands; //Array of commands for the Close button Command[] offCommands; //Undo command: Undo the last action Command undoCommand; //Constructor: Complete initialization of buttons public RemoteController() { onCommands = new Command[5]; offCommands = new Command[5]; for(int i = 0; i < 5; i++) { onCommands[i] = new NoCommand(); offCommands[i] = new NoCommand(); } undoCommand = new NoCommand(); } //Set the command needed for the button //no represents the set of switch commands (i.e., the line of commands); Turn on and off as a group public void setCommand(int no, Command onCommand, Command offCommand) { onCommands[no] = onCommand; offCommands[no] = offCommand; } //What to do after pressing the On button public void onButtonWasPushed(int no) { //Find the pressed Open button and call the appropriate method onCommands[no].execute(); //Record this action for undo undoCommand = onCommands[no]; } //Processing by pressing the "off" button public void offButtonWasPushed(int no) { offCommands[no].execute(); undoCommand = offCommands[no]; } //Processing by pressing the Undo button public void undoButtonWasPushed() { undoCommand.undo(); } } // Client.java public class Client { public static void main(String[] args) { //Complete lamp operation with remote control using command design mode //Create the object of the lamp (receiver) LightReceiver lightReceiver = new LightReceiver(); //Create lamp-related switch commands LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver); LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver); //Need a remote control RemoteController remoteController = new RemoteController(); //Set commands for the remote control: for example, no=0 corresponds to the switch on and off of the lamp remoteController.setCommand(0, lightOnCommand, lightOffCommand); System.out.println("=======Press the light on button======="); remoteController.onButtonWasPushed(0); System.out.println("=======Press the light off button======="); remoteController.offButtonWasPushed(0); System.out.println("========Press the Undo button========"); remoteController.undoButtonWasPushed(); } }
4. Notes and Details
- Core idea: decouple the object that initiates the request from the object that executes it. The object that initiates the request is the caller. The caller can make the receiver work by calling the execute() method of the command object without knowing who the specific recipient object is and how it is implemented. The command object is responsible for letting the recipient perform the requested action, that is, decoupling between the "request initiator" and the "request executor" is done through the command object. The command object acts as a bridge.
- Using command mode makes it easy to design a command queue. Command objects can be executed in multiple threads as long as they are queued
- Insufficient command mode: may cause some systems to have too many specific command classes, which increases the complexity of the system, which should be noted when using
- Empty commands are also a design pattern that eliminates the need for null commands. In the above example, if there is no empty command, we will be empty every time we press a key, which brings some trouble to our coding.