定義:定義一個算法的框架柑土,并允許子類提供框架中一個或多個步驟的具體實現。模版方法將算法的步驟實現交由子類決定眠屎,并且不會影響算法結構音同。
代碼示例
/**
* 模版抽象類,定義算法結構
*/
public abstract class AbstractClass{
// 也可定義為抽象方法料祠,每個抽象方法都需要實現
protected void method1(){};
protected void method2(){};
public final void templateMethod(){
this.method1();
this.method2();
}
}
/**
* 子類實現某個步驟
*/
public class ConcreteClass extends AbstractClass{
@Override
protected void method1(){};
}
public static void main(String[] args) {
AbstractClass abstractClass=new ConcreteClass();
abstractClass.templateMethod();
}
來看下spring中模版方法的使用
JdbcTemplate
:
//留意到JdbcTemplate的繼承關系
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
// 主要看這個方法講解骆捧,實現JdbcOperations的接口
@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
接口,從注釋就能明白這個接口的作用髓绽,以及JdbcTemplate所負責的功能敛苇。不得不強調良好的注釋,能增加源碼的可讀性顺呕。
@FunctionalInterface
public interface StatementCallback<T> {
/**
* Gets called by {@code JdbcTemplate.execute} with an active JDBC
* Statement. Does not need to care about closing the Statement or the
* Connection, or about handling transactions: this will all be handled
* by Spring's JdbcTemplate.
* <p><b>NOTE:</b> Any ResultSets opened should be closed in finally blocks
* within the callback implementation. Spring will close the Statement
* object after the callback returned, but this does not necessarily imply
* that the ResultSet resources will be closed: the Statement objects might
* get pooled by the connection pool, with {@code close} calls only
* returning the object to the pool but not physically closing the resources.
* <p>If called without a thread-bound JDBC transaction (initiated by
* DataSourceTransactionManager), the code will simply get executed on the
* JDBC connection with its transactional semantics. If JdbcTemplate is
* configured to use a JTA-aware DataSource, the JDBC connection and thus
* the callback code will be transactional if a JTA transaction is active.
* <p>Allows for returning a result object created within the callback, i.e.
* a domain object or a collection of domain objects. Note that there's
* special support for single step actions: see JdbcTemplate.queryForObject etc.
* A thrown RuntimeException is treated as application exception, it gets
* propagated to the caller of the template.
* @param stmt active JDBC Statement
* @return a result object, or {@code null} if none
* @throws SQLException if thrown by a JDBC method, to be auto-converted
* to a DataAccessException by an SQLExceptionTranslator
* @throws DataAccessException in case of custom exceptions
* @see JdbcTemplate#queryForObject(String, Class)
* @see JdbcTemplate#queryForRowSet(String)
*/
@Nullable
T doInStatement(Statement stmt) throws SQLException, DataAccessException;
}
那么JdbcTemplate
如何調用execute方法的呢枫攀,且看query方法
@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 + "]");
}
// 定義模版方法的具體一個步驟
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() {
return sql;
}
}
// 提供具體實現類括饶,實現execute某一步驟的自定義
return execute(new QueryStatementCallback());
}
可以看到StatementCallback的實現類:
image.png
Spring中1以Template結尾命名的類都是用的模板方法模式,同樣的影子在RestTemplate脓豪、RedisTemplate等類中也能發(fā)現巷帝。