目录
前言
学习命令模式痛苦的地方就是很多用不到,
真正开发也很少会刻意去写,就算用到也是有几个比较常见的
但还是得逼着自己看设计模式。。。
为了实现下一步研究spring源码的目标,硬着头皮去看点喽
接下来计划学习访问者模式、迭代者模式、观察者模式。。。一步步来吧
计划9月底前把设计模式过一遍,然后就可以看看一些源码,理论结合实战才能印象更深刻
今天简单学习了一波命令模式 【Command Pattern】
听这名字就知道命令模式是用来下发命令的
命令的下发者和命令的执行者,在命令模式中用中间的类Commond来解耦
命名模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦。
下面我们就一起来进一步了解命令模式
通用类图
Invoker是下发命令的角色,可以理解成将军,Command是一个抽象的命令接口
ConcreteCommond是具体的命令,比如是帮助将军下发命令的副将或者亲卫,当副将掏出剑就全线进攻
当亲卫鸣金就收兵,而Receiver就算命令的接收者,收到命令后就实施具体动作,前进还是撤
其实Reciver也可以抽出一个类,具体的接收者来继承,一个具体的命令,绑定一个具体的对象,这样来搞
但是设计模式从来都没有定的,规矩是死的,人是活,就算是jdk的编写者,还是写spring的大神,用起来设计模式往往和我们用的不大一样
命令模式也一样,用法也比较灵活,基本思想是解耦命令下发者和命令实施者
下面我们看一个简单的例子
实例
录音机(命令接收者)
public class AudioPlayer {
public void play(){
System.out.println("播放!");
}
public void rewind(){
System.out.println("倒带!");
}
public void stop(){
System.out.println("停止!");
}
}
命令接口
public interface Command {
AudioPlayer myAudio = new AudioPlayer();
/**
* 执行方法
*/
public void execute();
}
具体命令-播放
public class PlayCommand implements Command {
@Override
public void execute() {
myAudio.play();
}
}
具体命令-倒带
public class RewindCommand implements Command{
@Override
public void execute() {
myAudio.rewind();
}
}
具体命令-停止
public class StopCommand implements Command {
@Override
public void execute() {
myAudio.stop();
}
}
命令调用者
public class PressInvoker { Command command = null; public void setCommand(Command command){ this.command = command; } public void action(){ command.execute(); } }
客户端测试
public class Main {
public static void main(String[] args){
PressInvoker invoker = new PressInvoker();
System.out.println("听一波录音机...");
Command command = new PlayCommand();
invoker.setCommand(command);
invoker.action();
System.out.println("错过了精彩部分,倒带...");
command = new RewindCommand();
invoker.setCommand(command);
invoker.action();
System.out.println("不听了,出去嗨,不做死肥宅");
command = new StopCommand();
invoker.setCommand(command);
invoker.action();
}
}
输出:
听一波录音机…
播放!
错过了精彩部分,倒带…
倒带!
不听了,出去嗨,不做死肥宅
停止!
这样就不用和命令实施者交互
刻意把Conmmand理解成命令传递者,大佬往往不直接下发命令,都给小弟说,小弟代发
JdbcTemplate
命令模式在Spring JdbcTemplate中的使用
@Override
public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
return result(query(sql, new RowMapperResultSetExtractor<>(rowMapper)));
}
点进去 org.springframework.jdbc.core.JdbcTemplate#query
这个就算传说中的invoker 命令下发者
@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.
具体Commond 匿名内部类
值得注意的是这里Commond和命令的接收者都是他
*/
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());
}
我们看到最后 return execute(xxx) 里面就算具体的Commond
StatementCallback
而这个就算命令接口,具体的命令去实现他
我们来看看这个玩意:
@FunctionalInterface
public interface StatementCallback<T> {
@Nullable
T doInStatement(Statement stmt) throws SQLException, DataAccessException;
}
具体Commond类需要实现这个接口的doInStatement
这四个就算具体的Commond
再点进去
@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());
}
}
StatementCallback
又是一个具体的action
action.doInstatement(stmt)
说点什么
您将是第一位评论人!