Source address: Command mode of design mode
catalog
-
Command Pattern: in software design, we often need to send a request 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 request receiver when the program is running. At this time, we can use the Command Pattern to design
-
The naming pattern makes the request sender and the request receiver decouple from each other and makes the calling relationship between objects more flexible and decoupled.
-
In naming mode, a request is encapsulated as an object so that different parameters can be used to represent different requests (i.e. naming), and the command mode also supports revocable operations.
-
Easy to understand: the general issues orders and the soldiers carry them out. There are several roles: General (order issuer), soldier (specific executor), Command (connecting general and soldier). Invoker is the caller (general), Receiver is the callee (soldier), and MyCommand is the Command, which implements the Command interface and holds the receiving object
- Fundamentals
Invoker: the caller role is also the command initiator.
Command: it is a command role. The commands to be executed are all here. It can be an interface or an abstract class.
Receiver: the role of the receiver of a command, which knows how to implement and execute an operation related to a command request.
ConcreteCommand: bind the receiver object to a command action, and call the corresponding action of the receiver to execute the command.
- Application cases
1. Demand
Write the program, use the command mode to complete the previous smart home appliance project. Use switch to control light, TV
2. UML class diagram
3. Code implementation
//Client test public class CommandClient { public static void main(String[] args) { //Using command mode, operate the light by remote control LightReceiver lightReceiver = new LightReceiver(); //Create light switch LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver); LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver); //Create a remote control RemoteController remoteController = new RemoteController(); remoteController.setCommand(0,lightOnCommand,lightOffCommand); System.out.println("==================open======================"); remoteController.onButtonWasPushed(0); System.out.println("==================close======================"); remoteController.offButtonWasPushed(0); System.out.println("==================revoke======================"); remoteController.undoButtonWasPushed(0); } }
//Remote control public class RemoteController { private Command[] onCommands; private Command[] offCommands; private Command undoCommand; /** * Construction method, five groups of switches */ public RemoteController() { onCommands = new Command[5]; offCommands = new Command[5]; //Construct empty command to avoid empty judgment for (int i = 0; i < 5; i++) { onCommands[i] = new NoCommand(); offCommands[i] = new NoCommand(); } } /** * Set the command to be sent to the button * @param no * @param onCommand * @param offCommand */ public void setCommand(int no,Command onCommand,Command offCommand){ onCommands[no] = onCommand; offCommands[no] = offCommand; } /** * Press the on button * @param no */ public void onButtonWasPushed(int no){ onCommands[no].execute(); undoCommand = onCommands[no]; } /** * Press the close button * @param no */ public void offButtonWasPushed(int no){ offCommands[no].execute(); undoCommand = offCommands[no]; } /** * Press the undo button * @param no */ public void undoButtonWasPushed(int no){ undoCommand.undo(); } }
public class LightReceiver { public void on(){ System.out.println("Light on..............."); } public void off(){ System.out.println("Lights off..............."); } }
public interface Command { /** * Perform action */ void execute(); /** * Undo operation */ void undo(); }
public class LightOffCommand implements Command { /** * Aggregate LightReceiver */ private LightReceiver lightReceiver; public LightOffCommand(LightReceiver lightReceiver) { this.lightReceiver = lightReceiver; } @Override public void execute() { lightReceiver.off(); } @Override public void undo() { lightReceiver.on(); } }
public class LightOnCommand implements Command { /** * Aggregate LightReceiver */ private LightReceiver lightReceiver; public LightOnCommand(LightReceiver lightReceiver) { this.lightReceiver = lightReceiver; } @Override public void execute() { lightReceiver.on(); } @Override public void undo() { lightReceiver.off(); } }
public class NoCommand implements Command { @Override public void execute() { } @Override public void undo() { } }
- Spring source code analysis
Source code analysis of the application of command mode in spring framework JdbcTemplate:
StatementCallback interface: similar to command interface
QueryStatementCallback: the inner class in the JdbcTemplate implements the command interface and also acts as the command receiver
JdbcTemplate: the caller of the command, in the execute method action.doInStatement(stmt) method, different implementation StatementCallback interface objects, corresponding to different doinstatement logic.
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { @Override @Nullable public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException { Assert.notNull(sql, "SQL must not be null"); Assert.notNull(rse, "ResultSetExtractor must not be null"); if (logger.isDebugEnabled()) { logger.debug("Executing SQL query [" + sql + "]"); } /** * Callback to execute the query. */ class QueryStatementCallback implements StatementCallback<T>, SqlProvider { @Override @Nullable public T doInStatement(Statement stmt) throws SQLException { ResultSet rs = null; try { rs = stmt.executeQuery(sql); return rse.extractData(rs); } finally { JdbcUtils.closeResultSet(rs); } } @Override public String getSql() { return sql; } } return execute(new QueryStatementCallback()); } @Override @Nullable public <T> T execute(StatementCallback<T> action) throws DataAccessException { Assert.notNull(action, "Callback object must not be null"); Connection con = DataSourceUtils.getConnection(obtainDataSource()); Statement stmt = null; try { stmt = con.createStatement(); applyStatementSettings(stmt); T result = action.doInStatement(stmt); handleWarnings(stmt); return result; } catch (SQLException ex) { // Release Connection early, to avoid potential connection pool deadlock // in the case when the exception translator hasn't been initialized yet. String sql = getSql(action); JdbcUtils.closeStatement(stmt); stmt = null; DataSourceUtils.releaseConnection(con, getDataSource()); con = null; throw translateException("StatementCallback", sql, ex); } finally { JdbcUtils.closeStatement(stmt); DataSourceUtils.releaseConnection(con, getDataSource()); } } }
- summary
-
Decouples the object that initiated the request from the object that executed it. The object that initiates the request is the caller. As long as the caller calls the execute() method of the command object, he can let the receiver work without knowing who the specific receiver object is and how it is implemented. The command object is responsible for letting the receiver perform the requested action. That is to say, the decoupling between the "request initiator" and "request executor" is realized by the command object , the command object acts as a bridge.
-
Easy to design a command queue. As long as you put the command object in the queue, you can execute commands in multiple threads
-
Easy to undo and redo requests
-
Insufficient command mode: some systems may have too many specific command classes, increasing the complexity of the system, which should be noted when using
-
Empty command is also a design pattern, which saves us the operation of empty judgment. In the above example, if we don't use the empty command, we will judge the blank every time we press a key, which brings us some trouble in coding.
-
Classic application scenario of command mode: a button in the interface is a command, which simulates the cancellation / recovery and trigger feedback mechanism of CMD (DOS command) order