意图:在一个方法中定义算法的骨架,将某些步骤延迟到子类中实现。
模板方法是我个人认为后端开发中最被低估的模式——它的价值在于把不变的部分固化在父类,把可变的部分留给子类,避免了重复代码。
UML 简述:抽象类定义 templateMethod(final,不可覆盖),调用一系列步骤方法——其中抽象方法由子类实现,钩子方法可选覆盖。
AbstractApplicationContext.refresh() —— 史上最强的模板方法
Spring 容器的启动过程是模板方法模式最宏大的展现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public final void refresh() throws BeansException { prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); initMessageSource(); initApplicationEventMulticaster(); onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); finishRefresh(); }
|
refresh() 定义了容器启动的完整骨架,其中 postProcessBeanFactory() 和 onRefresh() 是留给子类的钩子:
1 2 3 4 5 6 7 8 9
| public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext { @Override protected void onRefresh() { createWebServer(); } }
|
JdbcTemplate —— 模板方法在数据访问中的典范
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public <T> T query(String sql, RowMapper<T> rowMapper) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = dataSource.getConnection(); ps = conn.prepareStatement(sql); rs = ps.executeQuery(); return rowMapper.mapRow(rs, 1); } catch (SQLException e) { throw new DataAccessException(e); } finally { JdbcUtils.closeResultSet(rs); JdbcUtils.closeStatement(ps); JdbcUtils.closeConnection(conn); } }
|
JdbcTemplate 将 JDBC 的 try-catch-finally 样板代码全部封装,开发者只需提供 SQL 和 RowMapper——“回调 + 模板方法“的混合模式。
InputStream 中的模板方法:JDK InputStream.read(byte[]) 的默认实现循环调用子类的 read(),父类定义”按字节填充数组”的骨架,子类只需实现单字节读取。