Java design pattern -- command pattern of behavior pattern

Source address: Command mode of design mode

catalog

  • Basic introduction

  1. 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

  2. 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.

  3. 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.

  4. 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

  1. 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.

  2. Easy to design a command queue. As long as you put the command object in the queue, you can execute commands in multiple threads

  3. Easy to undo and redo requests

  4. Insufficient command mode: some systems may have too many specific command classes, increasing the complexity of the system, which should be noted when using

  5. 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.

  6. 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

Tags: SQL Spring

Posted on Sat, 27 Jun 2020 02:22:40 -0400 by Kev