Java 模板方法模式是一種行為型設計模式,它定義了一個算法的骨架,并將一些步驟延遲到子類中實現。模板方法模式使得子類可以在不改變算法結構的情況下重定義算法中的某些步驟。
使用場景
- 算法骨架固定:如果一個算法的基本結構已經固定,但具體的實現步驟可能因為不同的場景而不同,這個時候可以使用模板方法模式。
- 實現代碼復用:如果有多個類的某些方法結構相似,但是實現細節不同,這個時候可以將這些相同的結構抽象到父類中,由子類來實現不同的細節。
- 簡化代碼實現:模板方法模式可以將復雜的代碼實現分離成幾個簡單的步驟,從而降低代碼實現的難度和復雜度。
- 框架和庫的設計:模板方法模式是設計框架和庫的重要方式之一,它可以提供統一的接口和標準的實現流程,方便用戶進行擴展和定制
代碼示例
AbstractClass 是一個抽象類,它定義了算法的骨架,其中 templateMethod() 是模板方法,它定義了算法的流程,由一些抽象方法 primitiveOperation1() 和 primitiveOperation2() 組成。
??ConcreteClass 是 AbstractClass 的具體子類,它實現了抽象方法,定義了具體的算法細節。在客戶端使用時,創建 ConcreteClass ,然后調用其 templateMethod() 方法,即可完成算法的執行。
代碼示例如下:
抽象類,定義算法骨架:
public abstract class AbstractClass {// 模板方法,定義算法流程public final void templateMethod() {primitiveOperation1();primitiveOperation2();}// 抽象方法1,由子類實現public abstract void primitiveOperation1();// 抽象方法2,由子類實現public abstract void primitiveOperation2();
}
具體子類,實現具體的算法細節:
public class ConcreteClass extends AbstractClass {@Overridepublic void primitiveOperation1() {System.out.println("ConcreteClass.primitiveOperation1()");}@Overridepublic void primitiveOperation2() {System.out.println("ConcreteClass.primitiveOperation2()");}
}
客戶端使用:
public class Client {public static void main(String[] args) {AbstractClass abstractClass = new ConcreteClass();abstractClass.templateMethod();}
}
需要注意的是,在模板方法模式中,模板方法通常被聲明為 final,以防止子類對其進行重寫。同時,由于模板方法是一個抽象方法,因此在實現時需要注意不同抽象方法的實現順序,以確保算法的正確性。
Spring 中的 JdbcTemplate
- 在 JdbcTemplate 類中,定義一個 execute 方法,該方法接收一個 ConnectionCallback 或 StatementCallback 對象作為參數。這些回調對象實現了具體的數據庫操作邏輯。
- 在 execute 方法中,根據傳入的回調對象類型,創建相應的 PreparedStatement 或 Statement 對象,并調用回調對象的 doInConnection 或 doInStatement 方法執行具體的數據庫操作。
- 將數據庫連接、PreparedStatement 或 Statement 對象等資源關閉的操作封裝在 finally 代碼塊中,確保資源能夠被正確釋放。
代碼如下:
public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {Assert.notNull(action, "Callback object must not be null");Connection con = DataSourceUtils.getConnection(obtainDataSource());try {Connection conToUse = createConnectionProxy(con);return action.doInConnection(conToUse);}catch (SQLException ex) {String sql = getSql(action);DataSourceUtils.releaseConnection(con, getDataSource());con = null;throw translateException("ConnectionCallback", sql, ex);}finally {DataSourceUtils.releaseConnection(con, getDataSource());}}
JdbcTemplate 類的 execute 方法接收一個 ConnectionCallback 對象作為參數,然后根據該對象執行具體的數據庫操作。這樣,JdbcTemplate 就實現了模板模式,將數據庫操作的具體邏輯封裝在 ConnectionCallback 對象中,而 JdbcTemplate 只負責管理數據庫連接和資源釋放。
優點
- 代碼復用性:模板模式通過將類的共同部分代碼抽象出來放在父類中,使得子類只需要實現差異部分,這大大減少了子類的重復代碼。
- 可擴展性:當需要新增功能時,可以通過子類來實現擴展,而不需要改動原有的代碼和代碼框架,這符合軟件設計的“開閉原則”,即對擴展開放,對修改封閉。
- 靈活性:所有子類實現的是同一套算法模型,在使用模板的地方,可以通過切換不同的子類來實不同的功能,這符合“里氏替換原則”。
- 維護性:由于模板模式的行為由父類控制,子類實現,這樣的結構清晰,有利于維護。
缺點
- 復雜性:對于一些簡單的任務,使用模板模式可能會引入不必要的復雜性。
- 繼承的限制:模板模式基于繼承,這意味著它可能不適用于所有的編程語言或框架,特別是那些不支持繼承的語言或框架。
- 設計習慣:我們平常的設計習慣可能更偏向于直接實現功能,而不是先定義一個模板方法,這可能需要一定的適應時間。