Click “like” to see, form a habit, the public account search [dime technology] pay attention to more original technical articles. This article has been included in GitHub org_Hejianhui /JavaStudy.

preface

  • 23 design modes for shorthand
  • The singleton pattern
  • Factory Method pattern
  • Abstract Factory pattern
  • The Builder/Builder pattern
  • Prototype mode
  • Flyweight mode
  • The facade pattern
  • Adapter mode
  • Decorator pattern
  • Observer mode
  • Strategy mode
  • Bridge mode
  • The Template Method pattern
  • The Chain of Responsibility model
  • Composite mode
  • Proxy mode
  • Memento mode
  • Updates continue at……

Here are 23 design patterns to memorize quicklyCommand modeRelated content.

The schema definition

Encapsulating a request as an object separates the responsibility for making the request from the responsibility for executing it. In this way, the two can communicate with each other through command objects. In this way, command objects can be stored, transferred, invoked, added and managed conveniently.

In software development system, there is a close coupling relationship between method requester and method implementor. This is not conducive to the expansion and maintenance of software functions. For example, it is inconvenient to “undo, redo, record” behavior, so “how do you decouple the requester of a method from the implementor of a method?” Becomes very important, and command mode is a good way to solve this problem.

The template implementation is as follows:

package com.niuh.designpattern.command.v1;

/** * 

* Command mode *

*/
public class CommandPattern { public static void main(String[] args) { Command cmd = new ConcreteCommand(); Invoker ir = new Invoker(cmd); System.out.println("The customer accesses the caller's call() method..."); ir.call(); }}// Abstract the command interface Command { public abstract void execute(a); } // Specify the command class ConcreteCommand implements Command { private Receiver receiver; ConcreteCommand() { receiver = new Receiver(); } public void execute(a) { receiver.action(); }}/ / the recipient class Receiver { public void action(a) { System.out.println("The receiver's action() method is called..."); }}/ / the caller class Invoker { private Command command; public Invoker(Command command) { this.command = command; } public void setCommand(Command command) { this.command = command; } public void call(a) { System.out.println("Caller executes command..."); command.execute(); }}Copy the code

The following output is displayed:

The customer accesses the caller's call() method... The caller executes command... The receiver's action() method is called...Copy the code

Problem solved

In a software system, the behavior requester and the behavior implementers are usually tightly coupled, but in some situations, such as the need to record, undo or redo the behavior, transaction, etc., such a tightly coupled design that cannot resist changes is not appropriate.

Patterns of

Related operations in the system can be abstracted into commands that separate the caller from the implementer. The structure is as follows.

To compose (a role). role
Abstract the Command class role Declare an interface to execute commands, with an abstract method execute() to execute commands.
Concrete Command roles Is a concrete implementation class of an abstract command class that owns the receiver object and performs the operations to be performed by the command by invoking the receiver’s functions.
Implementer/Receiver role The operations related to command functions are the implementers of specific command object services.
The caller/requester (Invoker) role Is the sender of the request, which usually has a number of command objects and executes the request by accessing the command object, not directly accessing the receiver.

Example is given to illustrate

Instance profiles

Combined with command mode, realize the opening and closing of a course video.

Using the step

Step 1: Declare the interface to execute the command and have an abstract method execute() to execute the command

interface Command {
    void execute(a);
}
Copy the code

Step 2: Define specific command roles to create open course links and close course links

/** * Open the course link */
class OpenCourseVideoCommand implements Command {

    private CourseVideo courseVideo;

    public OpenCourseVideoCommand(CourseVideo courseVideo) {
        this.courseVideo = courseVideo;
    }

    @Override
    public void execute(a) { courseVideo.open(); }}/** * close the course link */
class CloseCourseVideoCommand implements Command {

    private CourseVideo courseVideo;

    public CloseCourseVideoCommand(CourseVideo courseVideo) {
        this.courseVideo = courseVideo;
    }

    @Override
    public void execute(a) { courseVideo.close(); }}Copy the code

Step 3: Define the receiver role to perform operations related to command functions and be the implementer of specific command object services

class CourseVideo {

    private String name;

    public CourseVideo(String name) {
        this.name = name;
    }

    public void open(a) {
        System.out.println(this.name + "Course video is open.");
    }

    public void close(a) {
        System.out.println(this.name + "Lesson video closed."); }}Copy the code

Step 4: Create the User object as the sender of the request, the requester role

class User {

    private List<Command> commands = new ArrayList<>();

    public void addCommand(Command command) {
        commands.add(command);
    }

    public void executeCommands(a) { commands.forEach(Command::execute); commands.clear(); }}Copy the code

Step 4: Test execution

public class CommandPattern {

    public static void main(String[] args) {
        // Command receiver
        CourseVideo courseVideo = new CourseVideo("Design Pattern Series");

        // Create command
        OpenCourseVideoCommand openCourseVideoCommand = new OpenCourseVideoCommand(courseVideo);
        CloseCourseVideoCommand closeCourseVideoCommand = new CloseCourseVideoCommand(courseVideo);

        // Create an executor
        User user = new User();

        // Add a command
        user.addCommand(openCourseVideoCommand);
        user.addCommand(closeCourseVideoCommand);

        / / executionuser.executeCommands(); }}Copy the code

The output

Design Mode course video series open. Design Mode series course video off.Copy the code

advantages

  1. Reduce coupling of the system. The command pattern decouples the object that invokes an operation from the object that implements the operation.
  2. Adding or deleting commands is very convenient. Using command mode to add and delete commands does not affect other classes, it meets the “open and close principle”, is more flexible for expansion.
  3. Macro commands can be implemented. Command mode can be combined with composite mode to assemble multiple commands into a composite command, known as a macro command.
  4. Easy to implement Undo and Redo operations. The command mode can be combined with the memo mode to realize command undo and restore.

disadvantages

A large number of concrete command classes can be generated. Because a specific command class needs to be designed for each specific operation, this increases the complexity of the system.

Application scenarios

The command execution process is complex and may vary, and additional operations need to be performed. In this case, the command mode is recommended

Extension of command mode

In software development, command mode is sometimes combined with composite mode, which forms macro command mode, also known as composite command mode. A macro command contains a set of commands that act as both a specific command and a caller. When executed, all the commands contained in it are recursively invoked. The detailed structure is shown as follows:

The template implementation is as follows:

package com.niuh.designpattern.command.v2;

import java.util.ArrayList;

/** * 

* Combined command mode *

*/
public class CompositeCommandPattern { public static void main(String[] args) { AbstractCommand cmd1 = new ConcreteCommand1(); AbstractCommand cmd2 = new ConcreteCommand2(); CompositeInvoker ir = new CompositeInvoker(); ir.add(cmd1); ir.add(cmd2); System.out.println("Client access caller's execute() method..."); ir.execute(); }}// Abstract the command interface AbstractCommand { public abstract void execute(a); } // Leaf component: command 1 class ConcreteCommand1 implements AbstractCommand { private CompositeReceiver receiver; ConcreteCommand1() { receiver = new CompositeReceiver(); } public void execute(a) { receiver.action1(); }}// Leaf component: command 2 class ConcreteCommand2 implements AbstractCommand { private CompositeReceiver receiver; ConcreteCommand2() { receiver = new CompositeReceiver(); } public void execute(a) { receiver.action2(); }}// Branch component: caller class CompositeInvoker implements AbstractCommand { private ArrayList<AbstractCommand> children = new ArrayList<AbstractCommand>(); public void add(AbstractCommand c) { children.add(c); } public void remove(AbstractCommand c) { children.remove(c); } public AbstractCommand getChild(int i) { return children.get(i); } public void execute(a) { for(Object obj : children) { ((AbstractCommand) obj).execute(); }}}/ / the recipient class CompositeReceiver { public void action1(a) { System.out.println("The receiver's action1() method is called..."); } public void action2(a) { System.out.println("The receiver's action2() method is called..."); }}Copy the code

The following output is displayed:

The client accesses the caller's execute() method... The receiver's action1() method is called... The receiver's action2() method is called...Copy the code

Command mode can also be combined with Memento mode, making it an undoable command mode

Application in source code

  • The scheduleXXX() method in the java.util.timer class
  • Java Concurrency Executor execute() method
  • Java. Lang. Reflect. Method the invoke () Method
  • org.springframework.jdbc.core.JdbcTemplate
  • .

Application in JdbcTemplate

The use of command patterns in JdbcTemplate does not follow the standard use of command patterns, just the same idea.

The JdbcTemplate class in Spring has the query() method, which defines an inner class, QueryStatementCallback, QueryStatementCallback implements the StatementCallback interface, which is also implemented by other classes, and has an abstract method, doInStatement(). Query () is called in execute().

StatementCallback plays the command role, and JdbcTemplate plays both the caller and receiver role. The class diagram above is just for your convenience. In fact, QueryStatementCallback and ExecuteStatementCallback are internal classes to the JdbcTemplate method, as shown in the source code.

Partial source code analysis

StatementCallback interface:

public interface StatementCallback<T> {
	T doInStatement(Statement stmt) throws SQLException, DataAccessException;
}
Copy the code

JdbcTemplate class:

public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
	// corresponds to a command issued by the caller
	@Override
	public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
		return query(sql, new RowMapperResultSetExtractor<T>(rowMapper));
	}
	// After a command is issued, a specific command is sent to the receiver for execution
	@Override
	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 + "]");
		}
		// An inner class that implements StatementCallback, equivalent to a concrete command
		class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
			@Override
			public T doInStatement(Statement stmt) throws SQLException {
				ResultSet rs = null;
				try {
					rs = stmt.executeQuery(sql);
					ResultSet rsToUse = rs;
					if(nativeJdbcExtractor ! =null) {
						rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);
					}
					return rse.extractData(rsToUse);
				}
				finally{ JdbcUtils.closeResultSet(rs); }}@Override
			public String getSql(a) {
				returnsql; }}return execute(new QueryStatementCallback());
	}
	// The receiver is the real executor of the command
	@Override
	public <T> T execute(StatementCallback<T> action) throws DataAccessException {
		Assert.notNull(action, "Callback object must not be null");
		Connection con = DataSourceUtils.getConnection(getDataSource());
		Statement stmt = null;
		try {
			Connection conToUse = con;
			if (this.nativeJdbcExtractor ! =null &&
					this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {
				conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
			}
			stmt = conToUse.createStatement();
			applyStatementSettings(stmt);
			Statement stmtToUse = stmt;
			if (this.nativeJdbcExtractor ! =null) {
				stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);
			}
			T result = action.doInStatement(stmtToUse);
			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.
			JdbcUtils.closeStatement(stmt);
			stmt = null;
			DataSourceUtils.releaseConnection(con, getDataSource());
			con = null;
			throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex);
		}
		finally{ JdbcUtils.closeStatement(stmt); DataSourceUtils.releaseConnection(con, getDataSource()); }}}Copy the code

PS: The above code is submitted to Github: github.com/Niuh-Study/…

GitHub Org_Hejianhui /JavaStudy GitHub Hejianhui /JavaStudy