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
- Reduce coupling of the system. The command pattern decouples the object that invokes an operation from the object that implements the operation.
- 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.
- 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.
- 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