命令模式
- 概述
- UML类图
- 代码栗子
- Spring源码体现
- 总结
概述
-
概述
命令模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。 -
作用
-
- 类关系解耦,命令发送者与接受者解耦,命令行为参数化
-
可扩展性提高
UML类图
代码栗子
- 命令角色
public abstract class AbstractCommand {
/**
* 将任务接受者交给子类
*/
protected AbstractReceiver receiver ;
public AbstractReceiver getReceiver() {
return receiver;
}
public void setReceiver(AbstractReceiver receiver) {
this.receiver = receiver;
}
public AbstractCommand(AbstractReceiver receiver) {
this.receiver = receiver;
}
/**
* 执行命令
*/
public abstract void execute() ;
}
public class CoderCommand extends AbstractCommand {
@Override
public AbstractReceiver getReceiver() {
return super.getReceiver();
}
@Override
public void setReceiver(AbstractReceiver receiver) {
super.setReceiver(receiver);
}
public CoderCommand(AbstractReceiver receiver) {
super(receiver);
}
public CoderCommand() {
super(new TestReceiver());
}
@Override
public void execute() {
super.receiver.doSomething();
}
}
public class TestCommand extends AbstractCommand{
@Override
public AbstractReceiver getReceiver() {
return super.getReceiver();
}
@Override
public void setReceiver(AbstractReceiver receiver) {
super.setReceiver(receiver);
}
public TestCommand(AbstractReceiver receiver) {
super(receiver);
}
public TestCommand() {
super(new TestReceiver());
}
@Override
public void execute() {
super.receiver.doSomething();
}
}
- 命令接受者
public abstract class AbstractReceiver {
/**
* 抽象接收者,定义每个接收者都必须完成的业务
*/
public abstract void doSomething();
}
public class CoderReceiver extends AbstractReceiver{
/**
* 抽象接收者,定义每个接收者都必须完成的业务
*/
@Override
public void doSomething(){
System.out.println("修改了一行bug");
}
}
public class TestReceiver extends AbstractReceiver{
/**
* 抽象接收者,定义每个接收者都必须完成的业务
*/
@Override
public void doSomething(){
System.out.println("处理了一个bug测试");
}
}
- 命令调用者
public class Caller {
private AbstractReceiver receiver;
/**
* 客户发出命令
* @param receiver receiver
*/
public void setCommand(AbstractReceiver receiver) {
this.receiver = receiver;
}
//执行客户的命令
public void action() {
this.receiver.doSomething();
}
}
- client
public class Main {
public static void main(String[] args) {
Caller zhangSan = new Caller() ;
System.out.println("客户张三");
AbstractReceiver coderReceiver =new CoderReceiver() ;
System.out.println("需要执行修改代码操作,找到了代码执行者,指派给他");
zhangSan.setCommand(coderReceiver);
zhangSan.action();
}
}
- 运行效果
Spring源码体现
熟记以下三种角色,一起来看下Spring是如何使用命令模式的
- 命令调用角色 => org.springframework.jdbc.core.JdbcTemplate#query(String s, ResultSetExtractor) ;
- 命令角色 =>org.springframework.jdbc.core.StatementCallback#doInStatement(Statement smt);
- 命令接受角色 =>org.springframework.jdbc.core.JdbcTemplate#execute(StatementCallback);
使用IDEA 双击shift查找类,进入org.springframework.jdbc.core.JdbcTemplate,找到query() 方法,找到query(final String sql, final ResultSetExtractor rse)。
源码如下:
@Override
@Nullable
public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
// 省略非核心代码...
/**
* 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());
}
在代码的QueryStatementCallback类中可以看到它实现了StatementCallback接口,这个接口只有一个方法 doInStatement(Statement stmt)。将命令参数化如图:
根据传递的命令不同,执行execute()。
源码如下:
@Override
@Nullable
public <T> T execute(StatementCallback<T> action) throws DataAccessException {
// 省略非关键代码 。。。
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());
}
finally {
JdbcUtils.closeStatement(stmt);
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
总结
- 命令模式牢记一点,行为发起者与行为执行者解耦
栗子 老师布置作业为了提高效率,会让学习委员去收作业本,同学们只需要把作业交给学习委员就行了。这里面的行为发起者与行为执行者是谁呢?思考ing