客戶代碼 C 調用服務代碼 S 的方法 A,S 在某個時機反向調用 C 提供的方法 B。B 即回調函數。三要素:
Java 中通過接口或函數式接口實現回調。
在抽象類中定義算法骨架(模板方法),將可變步驟延遲到子類實現(鉤子方法/抽象方法)。優勢:
final 修飾模板方法防止被覆寫,保護算法結構。public abstract class AbstractTemplate {
// 模板方法:final 鎖定流程
public final void execute() {
step1();
step2(); // 可變步驟
step3();
}
private void step1() { System.out.println("通用前置:初始化資源"); }
protected abstract void step2(); // 子類必須實現
private void step3() { System.out.println("通用後置:釋放資源"); }
}
public class ConcreteImpl extends AbstractTemplate {
@Override protected void step2() { System.out.println("具體業務邏輯"); }
}
若抽象類有 10 個抽象方法,子類必須全部實現,即使只關心其中一個。且單繼承限制導致無法復用其他邏輯。
將可變步驟提取為獨立接口,作為方法參數傳入,模板類不再需要被繼承。
@FunctionalInterface // Java 8+ 函數式接口,支持 Lambda
public interface StatementCallback<T> {
T doInStatement(Statement stmt) throws SQLException;
}
public class JdbcTemplate {
// 模板方法:接收回調對象
public <T> T execute(StatementCallback<T> callback) throws SQLException {
Connection con = null;
Statement stmt = null;
try {
con = DataSourceUtil.getConnection(); // 1. 獲取連接
stmt = con.createStatement(); // 2. 創建 Statement
T result = callback.doInStatement(stmt); // 3. 回調:執行具體 SQL 與結果映射
return result;
} catch (SQLException e) {
throw e;
} finally {
// 4. 統一資源關閉 (模板固化)
closeQuietly(stmt);
closeQuietly(con);
}
}
}
JdbcTemplate template = new JdbcTemplate();
List<User> users = template.execute(stmt -> {
ResultSet rs = stmt.executeQuery("SELECT * FROM user");
List<User> list = new ArrayList<>();
while (rs.next()) {
User u = new User();
u.setId(rs.getInt("id"));
u.setName(rs.getString("name"));
list.add(u);
}
return list;
});
Spring 進一步將「結果集遍歷」與「單行映射」分離:
T mapRow(ResultSet rs, int rowNum) —— 單行映射為對象。T extractData(ResultSet rs) —— 整個結果集提取為集合/對象。模板方法內部組合:
public <T> List<T> query(String sql, RowMapper<T> rowMapper) {
return execute(new ResultSetExtractor<List<T>>() {
public List<T> extractData(ResultSet rs) {
List<T> results = new ArrayList<>();
int rowNum = 0;
while (rs.next()) {
results.add(rowMapper.mapRow(rs, rowNum++));
}
return results;
}
});
}
使用時只需關注單行映射:
List<User> users = jdbcTemplate.query("SELECT * FROM user", (rs, rowNum) -> {
User u = new User();
u.setId(rs.getInt("id"));
u.setName(rs.getString("name"));
return u;
});
JdbcOperations 接口 + JdbcAccessor 管理 DataSource/異常轉換,構建了完整生態。「模板方法定義骨架,回調注入變化」是框架設計的經典範式。從 JDBC 模板到事務模板 (TransactionTemplate)、Redis 模板 (RedisTemplate),Spring 全家桶無不體現此思想。掌握此模式,不僅能寫出可復用的工具類,更能深度理解主流框架的擴展機制。