美文网首页
【设计模式】- 模板方法模式

【设计模式】- 模板方法模式

作者: DoubleFooker | 来源:发表于2020-03-17 22:20 被阅读0次

    定义:定义一个算法的框架,并允许子类提供框架中一个或多个步骤的具体实现。模版方法将算法的步骤实现交由子类决定,并且不会影响算法结构。

    代码示例

    /**
    * 模版抽象类,定义算法结构
    */
    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等类中也能发现。

    相关文章

      网友评论

          本文标题:【设计模式】- 模板方法模式

          本文链接:https://www.haomeiwen.com/subject/miqddhtx.html