Welcome everyone

命令模式

设计模式 汪明鑫 901浏览 0评论

前言

学习命令模式痛苦的地方就是很多用不到,

真正开发也很少会刻意去写,就算用到也是有几个比较常见的

但还是得逼着自己看设计模式。。。

为了实现下一步研究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)

 

 

转载请注明:汪明鑫的个人博客 » 命令模式

喜欢 (0)

说点什么

您将是第一位评论人!

提醒
avatar
wpDiscuz