定义:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
一、简单例子:
下面先以一个简单的例子说明一下:
抽象模板类:
package template; public abstract class RoastFish { //通用的步骤:加水 void addWater() { System.out.println("加水"); } //需要定制化的步骤:加哪种鱼(子类定义算法的某些步骤) abstract void addFish(); //通用的步骤:加调料 void addSeasoning() { System.out.println("加调料"); } //通用的步骤:烤制 void roast() { System.out.println("烤制"); } //模板方法,它被声明为final,以免子类改变这个算法的顺序。 public final void cooking() { addWater(); addFish(); addSeasoning(); roast(); System.out.println("烤制完成,出锅"); } }
烤鲈鱼子类:
package template; public class RoastLuYu extends RoastFish { @Override void addFish() { System.out.println("添加鲈鱼"); } }
烤鲟鱼子类:
package template; public class RoastXunYu extends RoastFish { @Override void addFish() { System.out.println("添加鲟鱼"); } }
测试类:
package template; public class Test { public static void main(String[] args) { RoastFish roastFish = new RoastLuYu(); roastFish.cooking(); System.out.println("-----****************------"); roastFish = new RoastXunYu(); roastFish.cooking(); } }
执行结果:
加水 添加鲈鱼 加调料 烤制 烤制完成,出锅 -----****************----- 加水 添加鲟鱼 加调料 烤制 烤制完成,出锅
二、***Template
spring提供的数据库访问的模板类JdbcTemplate、消息处理的模板类JMSTemplate、HTTP通信的模板类RestTemplate,也是使用了模板设计模式,但不是上述例子中最典型的模板模式,是一种更简洁、更适合于编码的使用方式。他没有抽象类,只有一个模板类,通用步骤在当前类中定义,需要定制化的步骤通过回调的方式定义。下面举例说明:
JdbcTemplate:
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { @Override @Nullable public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action) throws DataAccessException { Assert.notNull(psc, "PreparedStatementCreator must not be null"); Assert.notNull(action, "Callback object must not be null"); if (logger.isDebugEnabled()) { String sql = getSql(psc); logger.debug("Executing prepared SQL statement" + (sql != null ? " [" + sql + "]" : "")); } //通用步骤:获取connection Connection con = DataSourceUtils.getConnection(obtainDataSource()); PreparedStatement ps = null; try {
//通用步骤:获取PrepareStatement ps = psc.createPreparedStatement(con);
//定制化步骤:设置PrepareStatement配置 applyStatementSettings(ps);
//定制化步骤:通过回调函数定制化对PrepareStatement的操作,即具体的查库操作 T result = action.doInPreparedStatement(ps); handleWarnings(ps); 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. if (psc instanceof ParameterDisposer) { ((ParameterDisposer) psc).cleanupParameters(); } String sql = getSql(psc);
//通用步骤:关闭PrepareStatement JdbcUtils.closeStatement(ps); ps = null;
//通用步骤:释放connection DataSourceUtils.releaseConnection(con, getDataSource()); con = null; throw translateException("PreparedStatementCallback", sql, ex); } finally { if (psc instanceof ParameterDisposer) { ((ParameterDisposer) psc).cleanupParameters(); } JdbcUtils.closeStatement(ps); DataSourceUtils.releaseConnection(con, getDataSource()); } } }
JmsTemplate:
public class JmsTemplate extends JmsDestinationAccessor implements JmsOperations { @Nullable public <T> T execute(SessionCallback<T> action, boolean startConnection) throws JmsException { Assert.notNull(action, "Callback object must not be null"); Connection conToClose = null; Session sessionToClose = null; try { Session sessionToUse = ConnectionFactoryUtils.doGetTransactionalSession( obtainConnectionFactory(), this.transactionalResourceFactory, startConnection); if (sessionToUse == null) {
//通用步骤:创建connection conToClose = createConnection();
//通用步骤:创建session sessionToClose = createSession(conToClose); if (startConnection) { conToClose.start(); } sessionToUse = sessionToClose; } if (logger.isDebugEnabled()) { logger.debug("Executing callback on JMS Session: " + sessionToUse); }
//定制化步骤:通过回调函数定制化处理具体的发送或者接收消息 return action.doInJms(sessionToUse); } catch (JMSException ex) { throw convertJmsAccessException(ex); } finally {
//通用步骤:关闭session JmsUtils.closeSession(sessionToClose);
//通用步骤:释放connection ConnectionFactoryUtils.releaseConnection(conToClose, getConnectionFactory(), startConnection); } } }
RestTemplate:
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations { protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException { Assert.notNull(url, "URI is required"); Assert.notNull(method, "HttpMethod is required"); ClientHttpResponse response = null; try {
//通用步骤:构造request ClientHttpRequest request = createRequest(url, method); if (requestCallback != null) {
//定制化步骤:通过回调的方式准备(配置)request requestCallback.doWithRequest(request); }
//通用步骤:执行请求 response = request.execute();
//通用步骤:处理响应 handleResponse(url, method, response);
//定制化步骤:通过回调的方式抽取响应中的返回值 return (responseExtractor != null ? responseExtractor.extractData(response) : null); } catch (IOException ex) { String resource = url.toString(); String query = url.getRawQuery(); resource = (query != null ? resource.substring(0, resource.indexOf('?')) : resource); throw new ResourceAccessException("I/O error on " + method.name() + " request for "" + resource + "": " + ex.getMessage(), ex); } finally { if (response != null) { response.close(); } } } }