【設計模式】- 模板方法模式

定義:定義一個算法的框架柑土,并允許子類提供框架中一個或多個步驟的具體實現。模版方法將算法的步驟實現交由子類決定眠屎,并且不會影響算法結構音同。

代碼示例

/**
* 模版抽象類,定義算法結構
*/
public abstract class AbstractClass{
// 也可定義為抽象方法料祠,每個抽象方法都需要實現
    protected void method1(){};
    protected void method2(){};
    public final void templateMethod(){
        this.method1();
        this.method2();
    }
}
/**
* 子類實現某個步驟
*/
    public class ConcreteClass extends AbstractClass{
        @Override
        protected void method1(){};
    }

    public static void main(String[] args) {
        AbstractClass abstractClass=new ConcreteClass();
        abstractClass.templateMethod();
    }

來看下spring中模版方法的使用
JdbcTemplate:

//留意到JdbcTemplate的繼承關系
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
        // 主要看這個方法講解骆捧,實現JdbcOperations的接口
    @Override
    @Nullable
    public <T> T execute(StatementCallback<T> action) throws DataAccessException {
        Assert.notNull(action, "Callback object must not be null");

        Connection con = DataSourceUtils.getConnection(obtainDataSource());
        Statement stmt = null;
        try {
            stmt = con.createStatement();
            applyStatementSettings(stmt);
                        // 模版的調用在這句
            T result = action.doInStatement(stmt);
            handleWarnings(stmt);
            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.
            String sql = getSql(action);
            JdbcUtils.closeStatement(stmt);
            stmt = null;
            DataSourceUtils.releaseConnection(con, getDataSource());
            con = null;
            throw translateException("StatementCallback", sql, ex);
        }
        finally {
            JdbcUtils.closeStatement(stmt);
            DataSourceUtils.releaseConnection(con, getDataSource());
        }
    }

}

在來看下StatementCallback接口,從注釋就能明白這個接口的作用髓绽,以及JdbcTemplate所負責的功能敛苇。不得不強調良好的注釋,能增加源碼的可讀性顺呕。

@FunctionalInterface
public interface StatementCallback<T> {

    /**
     * Gets called by {@code JdbcTemplate.execute} with an active JDBC
     * Statement. Does not need to care about closing the Statement or the
     * Connection, or about handling transactions: this will all be handled
     * by Spring's JdbcTemplate.
     * <p><b>NOTE:</b> Any ResultSets opened should be closed in finally blocks
     * within the callback implementation. Spring will close the Statement
     * object after the callback returned, but this does not necessarily imply
     * that the ResultSet resources will be closed: the Statement objects might
     * get pooled by the connection pool, with {@code close} calls only
     * returning the object to the pool but not physically closing the resources.
     * <p>If called without a thread-bound JDBC transaction (initiated by
     * DataSourceTransactionManager), the code will simply get executed on the
     * JDBC connection with its transactional semantics. If JdbcTemplate is
     * configured to use a JTA-aware DataSource, the JDBC connection and thus
     * the callback code will be transactional if a JTA transaction is active.
     * <p>Allows for returning a result object created within the callback, i.e.
     * a domain object or a collection of domain objects. Note that there's
     * special support for single step actions: see JdbcTemplate.queryForObject etc.
     * A thrown RuntimeException is treated as application exception, it gets
     * propagated to the caller of the template.
     * @param stmt active JDBC Statement
     * @return a result object, or {@code null} if none
     * @throws SQLException if thrown by a JDBC method, to be auto-converted
     * to a DataAccessException by an SQLExceptionTranslator
     * @throws DataAccessException in case of custom exceptions
     * @see JdbcTemplate#queryForObject(String, Class)
     * @see JdbcTemplate#queryForRowSet(String)
     */
    @Nullable
    T doInStatement(Statement stmt) throws SQLException, DataAccessException;

}

那么JdbcTemplate如何調用execute方法的呢枫攀,且看query方法

    @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;
            }
        }
        // 提供具體實現類括饶,實現execute某一步驟的自定義
        return execute(new QueryStatementCallback());
    }

可以看到StatementCallback的實現類:


image.png

Spring中1以Template結尾命名的類都是用的模板方法模式,同樣的影子在RestTemplate脓豪、RedisTemplate等類中也能發(fā)現巷帝。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市扫夜,隨后出現的幾起案子楞泼,更是在濱河造成了極大的恐慌,老刑警劉巖笤闯,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件堕阔,死亡現場離奇詭異,居然都是意外死亡颗味,警方通過查閱死者的電腦和手機超陆,發(fā)現死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來浦马,“玉大人时呀,你說我怎么就攤上這事【” “怎么了谨娜?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長磺陡。 經常有香客問我趴梢,道長,這世上最難降的妖魔是什么币他? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任坞靶,我火速辦了婚禮,結果婚禮上蝴悉,老公的妹妹穿的比我還像新娘彰阴。我一直安慰自己,他們只是感情好拍冠,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布硝枉。 她就那樣靜靜地躺著,像睡著了一般倦微。 火紅的嫁衣襯著肌膚如雪妻味。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天欣福,我揣著相機與錄音责球,去河邊找鬼。 笑死,一個胖子當著我的面吹牛雏逾,可吹牛的內容都是我干的嘉裤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼栖博,長吁一口氣:“原來是場噩夢啊……” “哼屑宠!你這毒婦竟也來了?” 一聲冷哼從身側響起仇让,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤典奉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后丧叽,有當地人在樹林里發(fā)現了一具尸體卫玖,經...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年踊淳,在試婚紗的時候發(fā)現自己被綠了假瞬。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡迂尝,死狀恐怖脱茉,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情垄开,我是刑警寧澤琴许,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站说榆,受9級特大地震影響,放射性物質發(fā)生泄漏寸认。R本人自食惡果不足惜签财,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望偏塞。 院中可真熱鬧唱蒸,春花似錦、人聲如沸灸叼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽古今。三九已至屁魏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捉腥,已是汗流浹背氓拼。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人桃漾。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓坏匪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親撬统。 傳聞我的和親對象是個殘疾皇子适滓,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內容