Smart Life project requirements
- We bought a set of smart appliances, including lights, fans, refrigerators and washing machines. We can control the work of these appliances as long as we install apps on our mobile phones.
- These smart appliances come from different manufacturers. We don't want to install an app for each kind of home appliance and control them separately. We hope that only one app can control all smart appliances.
- To realize the need for an app to control all smart appliances, each smart appliance manufacturer should provide a unified interface for app calls. At this time, the command mode can be considered.
- Command mode decouples the action requester from the action performer object
- In our example, the requester of the action is a mobile app, and the executor of the action is a household appliance of each manufacturer
Command mode
Basic introduction
- Command Pattern: in software design, we often need to send requests to some objects, but we don't know who the receiver of the request is or what the requested operation is. We just need to specify the specific receiver of the request when the program is running. At this time, we can use the Command Pattern for design
- The naming pattern makes the request sender and the request receiver eliminate the coupling between each other, makes the call relationship between objects more flexible and realizes decoupling.
- In the naming mode, a request is encapsulated into an object to represent different requests (i.e. naming) with different parameters. At the same time, the command mode also supports revocable operations.
- The general gives orders and the soldiers carry them out. There are several roles: General (the order issuer), soldier (the specific executor of the order), and Command (connecting general and soldier). Invoker is the caller (general), Receiver is the callee (soldier), and MyCommand is the Command. It implements the Command interface and holds the receiving object
Schematic class diagram
- Invoker is the caller role
- Command: is a command role. All commands to be executed are here. They can be interfaces or abstract classes
- Receiver: the receiver role, which knows how to implement and execute a request related operation
- ConcreteCommand: bind a receiver object to an action, call the corresponding operation of the receiver, and implement execute
Command mode to solve intelligent life project
Train of thought analysis and illustration
package com.atguigu.command; //Create command interface public interface Command { //Execute action (operation) public void execute(); //Undo action public void undo(); }
package com.atguigu.command; public class LightOnCommand implements Command { //Aggregate LightReceiver LightReceiver light; //constructor public LightOnCommand(LightReceiver light) { super(); this.light = light; } @Override public void execute() { // TODO Auto-generated method stub //Call the recipient's method light.on(); } @Override public void undo() { // TODO Auto-generated method stub //Call the recipient's method light.off(); } }
package com.atguigu.command; public class LightOffCommand implements Command { // Aggregate LightReceiver LightReceiver light; // constructor public LightOffCommand(LightReceiver light) { super(); this.light = light; } @Override public void execute() { // TODO Auto-generated method stub // Call the recipient's method light.off(); } @Override public void undo() { // TODO Auto-generated method stub // Call the recipient's method light.on(); } }
package com.atguigu.command; /** * No command, i.e. empty execution: used to initialize each button. When the empty command is called, the object does nothing * In fact, this is a design mode, which can eliminate the judgment of air * @author Administrator * */ public class NoCommand implements Command { @Override public void execute() { // TODO Auto-generated method stub } @Override public void undo() { // TODO Auto-generated method stub } }
package com.atguigu.command; public class LightReceiver { public void on() { System.out.println(" The light is on.. "); } public void off() { System.out.println(" The lights are off.. "); } }
package com.atguigu.command; public class TVOnCommand implements Command { // Aggregate TVReceiver TVReceiver tv; // constructor public TVOnCommand(TVReceiver tv) { super(); this.tv = tv; } @Override public void execute() { // TODO Auto-generated method stub // Call the recipient's method tv.on(); } @Override public void undo() { // TODO Auto-generated method stub // Call the recipient's method tv.off(); } }
package com.atguigu.command; public class TVOffCommand implements Command { // Aggregate TVReceiver TVReceiver tv; // constructor public TVOffCommand(TVReceiver tv) { super(); this.tv = tv; } @Override public void execute() { // TODO Auto-generated method stub // Call the recipient's method tv.off(); } @Override public void undo() { // TODO Auto-generated method stub // Call the recipient's method tv.on(); } }
package com.atguigu.command; public class TVReceiver { public void on() { System.out.println(" The TV is on.. "); } public void off() { System.out.println(" The TV is off.. "); } }
package com.atguigu.command; public class RemoteController { // Command array of on button Command[] onCommands; Command[] offCommands; // Execute undo command Command undoCommand; // Constructor to complete the initialization of the button 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(); } } // Give our buttons the commands you need public void setCommand(int no, Command onCommand, Command offCommand) { onCommands[no] = onCommand; offCommands[no] = offCommand; } // Press the on button public void onButtonWasPushed(int no) { // no 0 // Find the on button you pressed and call the corresponding method onCommands[no].execute(); // Record this operation for cancellation undoCommand = onCommands[no]; } // Press the on button public void offButtonWasPushed(int no) { // no 0 // Find the off button you pressed and call the corresponding method offCommands[no].execute(); // Record this operation for cancellation undoCommand = offCommands[no]; } // Press the undo button public void undoButtonWasPushed() { undoCommand.undo(); } }
package com.atguigu.command; public class Client { public static void main(String[] args) { // TODO Auto-generated method stub //Use the command design mode to complete the operation of the electric lamp through the remote control //Create the object of the light (receiver) LightReceiver lightReceiver = new LightReceiver(); //Create light related switch commands LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver); LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver); //Need a remote control RemoteController remoteController = new RemoteController(); //Set commands for our remote control, such as no = 0, which is the operation of turning on and off the electric light remoteController.setCommand(0, lightOnCommand, lightOffCommand); System.out.println("--------Press the on button of the light-----------"); remoteController.onButtonWasPushed(0); System.out.println("--------Press the light off button-----------"); remoteController.offButtonWasPushed(0); System.out.println("--------Press the undo button-----------"); remoteController.undoButtonWasPushed(); System.out.println("=========Operate the TV with the remote control=========="); TVReceiver tvReceiver = new TVReceiver(); TVOffCommand tvOffCommand = new TVOffCommand(tvReceiver); TVOnCommand tvOnCommand = new TVOnCommand(tvReceiver); //Set commands for our remote control, such as no = 1, which is the operation of turning on and off the TV remoteController.setCommand(1, tvOnCommand, tvOffCommand); System.out.println("--------Press the on button on the TV-----------"); remoteController.onButtonWasPushed(1); System.out.println("--------Press the off button on the TV-----------"); remoteController.offButtonWasPushed(1); System.out.println("--------Press the undo button-----------"); remoteController.undoButtonWasPushed(); } }
Precautions and details of command mode
- Decouple the object that initiates the request from the object that executes the request. The object initiating the request is the caller. The caller can let the receiver work as long as he calls the execute() method of the command object, without knowing who the specific receiver object is and how to implement it. The command object will be responsible for letting the receiver execute the requested action, In other words, the decoupling between "request initiator" and "request executor" is realized through the command object, which acts as a bridge.
- Easy to design a command queue. As long as the command object is queued, the command can be executed in multiple threads
- It is easy to undo and redo the request
- Insufficient command mode: some systems may have too many specific command classes, increasing the complexity of the system, which should be paid attention to when using
- Empty command is also a design mode, which saves us the operation of judging empty. In the above example, if we don't use the empty command, we will judge it empty every time we press a key, which brings us some trouble in coding.
- The classic application scenario of command mode: a button on the interface is a command, simulating the cancellation / recovery of CMD (DOS command) order and trigger feedback mechanism