正文前先來一波福利推薦:
福利一:
百萬年薪架構師視頻,該視頻可以學到很多東西,是本人花錢買的VIP課程,學習消化了一年,為了支持一下女朋友公眾號也方便大家學習,共享給大家。
福利二:
畢業答辯以及工作上各種答辯,平時積累了不少精品PPT,現在共享給大家,大大小小加起來有幾千套,總有適合你的一款,很多是網上是下載不到。
獲取方式:
微信關注 精品3分鍾 ,id為 jingpin3mins,關注后回復 百萬年薪架構師 ,精品收藏PPT 獲取雲盤鏈接,謝謝大家支持!
-----------------------正文開始---------------------------
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方法俗稱鈎子方法。有了鈎子方法的模板方法模式才算完美,使得我們的控制行為更加的主動,更加的靈活。