命令模式

  • 概述
  • UML类图
  • 代码栗子
  • Spring源码体现
  • 总结

概述

  • 概述
    命令模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。

  • 作用

    1. 类关系解耦,命令发送者与接受者解耦,命令行为参数化
  1. 可扩展性提高

UML类图

image.png

代码栗子

  • 命令角色
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();
    }
}
  • 运行效果

image.png

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)。将命令参数化如图:

img

根据传递的命令不同,执行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
原文地址:https://www.cnblogs.com/tanoak/p/11911859.html