1、使用背景
模板方法模式是通过把不变行为搬到超类,去除子类里面的重复代码提现它的优势,它提供了一个很好的代码复用平台。当不可变和可变的方法在子类中混合在一起的时候,
不变的方法就会在子类中多次出现,这样如果摸个方法需要修改则需要修改很多个,虽然这个这个问题在设计之初就应该想好。这个时候模板方法模式就起到了作用了,
通过模板方法模式把这些重复出现的方法搬到单一的地方,这样就可以帮助子类摆脱重复不变的纠缠。
2、已Spring中的 JdbcTemplate 使用模板模式为例 说明其优越之处;
方法 execute(StatementCallback<T> sc) 方法公共方法,里边封装了可复用代码;
参数StatementCallback是一个接口 接口方法是 doInStatement() 该方法是实现不同操作的方法;也就是不同的实现在这里呈现;
public <L> L execute(StatementCallback<L> action) { try{ 1. 加载驱动 2. 建立连接 3. 获取Statement stmt
4. 拼接参数
} catch(Exception e) { }
try{
synchronized (this) //使用同步锁 保护线程安全
{
return action.doInStatement(session);
}
}catch (HibernateException ex)
{
throw new Exception(ex);
}catch (SQLException ex) {
}
finally{ 7. 销毁连接 } } }
@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; } } //真正执行的方法 return execute(new QueryStatementCallback()); }
调用query方法的时候 会执行execute方法,该方法为模板方法,然后因为该方法内部调用传入的 StatementCallback 接口的 doInStatement 方法 但是该方法可以在query方法中通过传入匿名内部类,自定义使用; 完全符合模板模式的使用;
1、使用钩子方法对模板不同行为进行控制
下面以一个汽车的例子来说明钩子方法的使用:
public abstract class HummerModel { protected abstract void start(); //发动 protected abstract void stop(); //停止 protected abstract void alarm(); //鸣笛 protected abstract void engineBoom(); //轰鸣 final public void run() { //车总归要跑 this.start(); this.engineBoom(); if(this.isAlarm()) {//想让它叫就叫,不想就不叫 this.alarm(); } this.stop(); } protected boolean isAlarm() { //我们加了一个判断方法,默认返回true return true; } }
public class HummerH1 extends HummerModel { private boolean alarmFlag = true; //判断标记 @Override public void start() { System.out.println("H1发动……"); } @Override public void stop() { System.out.println("H1停止……"); } @Override public void alarm() { System.out.println("H1鸣笛……"); } @Override public void engineBoom() { System.out.println("H1轰鸣……"); } @Override protected boolean isAlarm() { //覆写isAlarm方法,返回判断标记 return this.alarmFlag; } public void setAlarm(boolean isAlarm) { //设置判断标记 this.alarmFlag = isAlarm; } }
这段代码中,我们在模板方法中增加了判断标记,然后子类对外提供一个public接口setAlarm来让外界设置这个判断标记,这个判断标记就像是开关一样,想让它ture和false都行。
这个isAlarm方法俗称钩子方法。有了钩子方法的模板方法模式才算完美,使得我们的控制行为更加的主动,更加的灵活。