博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【01】模板模式
阅读量:6823 次
发布时间:2019-06-26

本文共 8151 字,大约阅读时间需要 27 分钟。

  hot3.png

1、上下文及问题

     某些操作,有一系列的固定步骤,其中只有少部分操作是变化了,没有模式的情况下,每次都需要重复大部分的固定步骤,重复工作多,另外如果这些大部分的操作是有顺序或规范的话,容易写错

2、常见的场景

(1)jdbc操作,如Spring JDBC Template

(2)分页查询数据文件下载写入

3、解决方式

    引入模板,将通用操作步骤固定起来,抽象出变化的部分

(1)抽象继承方式:让子类去重写个性化的内容

(2)组合回调方式:Java采用匿名类,Scala采用函数参数

4、模式抽象图

090406_zbD4_1383356.png

    templateMethod()里头封装了一些模板方法,然后将个性化的部分,以subMethod方式给以子类重写,达到个性化目的。

    但通常,不大使用这种继承的实现方法,一般采用匿名接口/函数传递的模式

5、代码示例

(1)Spring JDBC Template

public Book findById2(Integer id){        return jdbcTemplate.query("select * from book where book_id=?",new Object[]{id},new RowMapper
() {            @Override            public Book mapRow(ResultSet rs, int rowNum) throws SQLException {                Book book = new Book();                book.setBookId(rs.getInt("book_id"));                book.setTitle(rs.getString("title"));                book.setCreatedAt(rs.getTimestamp("created_at"));                return book;            }        }).get(0);    }

   接口

/** * Callback interface used by {@link JdbcTemplate}'s query methods. * Implementations of this interface perform the actual work of extracting * results from a {@link java.sql.ResultSet}, but don't need to worry * about exception handling. {@link java.sql.SQLException SQLExceptions} * will be caught and handled by the calling JdbcTemplate. * * 

This interface is mainly used within the JDBC framework itself. * A {@link RowMapper} is usually a simpler choice for ResultSet processing, * mapping one result object per row instead of one result object for * the entire ResultSet. * * 

Note: In contrast to a {@link RowCallbackHandler}, a ResultSetExtractor * object is typically stateless and thus reusable, as long as it doesn't * access stateful resources (such as output streams when streaming LOB * contents) or keep result state within the object. * * @author Rod Johnson * @author Juergen Hoeller * @since April 24, 2003 * @see JdbcTemplate * @see RowCallbackHandler * @see RowMapper * @see org.springframework.jdbc.core.support.AbstractLobStreamingResultSetExtractor */public interface ResultSetExtractor

 { /**  * Implementations must implement this method to process the entire ResultSet.  * @param rs ResultSet to extract data from. Implementations should  * not close this: it will be closed by the calling JdbcTemplate.  * @return an arbitrary result object, or {@code null} if none  * (the extractor will typically be stateful in the latter case).  * @throws SQLException if a SQLException is encountered getting column  * values or navigating (that is, there's no need to catch SQLException)  * @throws DataAccessException in case of custom exceptions  */ T extractData(ResultSet rs) throws SQLException, DataAccessException;}

   接口实现

/** * Adapter implementation of the ResultSetExtractor interface that delegates * to a RowMapper which is supposed to create an object for each row. * Each object is added to the results List of this ResultSetExtractor. * * 

Useful for the typical case of one object per row in the database table. * The number of entries in the results list will match the number of rows. * * 

Note that a RowMapper object is typically stateless and thus reusable; * just the RowMapperResultSetExtractor adapter is stateful. * * 

A usage example with JdbcTemplate: * * 

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);  // reusable object * RowMapper rowMapper = new UserRowMapper();  // reusable object * * List allUsers = (List) jdbcTemplate.query( *     "select * from user", *     new RowMapperResultSetExtractor(rowMapper, 10)); * * User user = (User) jdbcTemplate.queryForObject( *     "select * from user where id=?", new Object[] {id}, *     new RowMapperResultSetExtractor(rowMapper, 1)); * * 

Alternatively, consider subclassing MappingSqlQuery from the {@code jdbc.object} * package: Instead of working with separate JdbcTemplate and RowMapper objects, * you can have executable query objects (containing row-mapping logic) there. * * @author Juergen Hoeller * @since 1.0.2 * @see RowMapper * @see JdbcTemplate * @see org.springframework.jdbc.object.MappingSqlQuery */public class RowMapperResultSetExtractor

 implements ResultSetExtractor
> { private final RowMapper
 rowMapper; private final int rowsExpected; /**  * Create a new RowMapperResultSetExtractor.  * @param rowMapper the RowMapper which creates an object for each row  */ public RowMapperResultSetExtractor(RowMapper
 rowMapper) { this(rowMapper, 0); } /**  * Create a new RowMapperResultSetExtractor.  * @param rowMapper the RowMapper which creates an object for each row  * @param rowsExpected the number of expected rows  * (just used for optimized collection handling)  */ public RowMapperResultSetExtractor(RowMapper
 rowMapper, int rowsExpected) { Assert.notNull(rowMapper, "RowMapper is required"); this.rowMapper = rowMapper; this.rowsExpected = rowsExpected; } @Override public List
 extractData(ResultSet rs) throws SQLException { List
 results = (this.rowsExpected > 0 ? new ArrayList
(this.rowsExpected) : new ArrayList
()); int rowNum = 0; while (rs.next()) { results.add(this.rowMapper.mapRow(rs, rowNum++)); } return results; }}

   模板调用

/**	 * Query using a prepared statement, allowing for a PreparedStatementCreator	 * and a PreparedStatementSetter. Most other query methods use this method,	 * but application code will always work with either a creator or a setter.	 * @param psc Callback handler that can create a PreparedStatement given a	 * Connection	 * @param pss object that knows how to set values on the prepared statement.	 * If this is null, the SQL will be assumed to contain no bind parameters.	 * @param rse object that will extract results.	 * @return an arbitrary result object, as returned by the ResultSetExtractor	 * @throws DataAccessException if there is any problem	 */	public 
 T query( PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor
 rse) throws DataAccessException { Assert.notNull(rse, "ResultSetExtractor must not be null"); logger.debug("Executing prepared SQL query"); return execute(psc, new PreparedStatementCallback
() { @Override public T doInPreparedStatement(PreparedStatement ps) throws SQLException { ResultSet rs = null; try { if (pss != null) { pss.setValues(ps); } rs = ps.executeQuery(); ResultSet rsToUse = rs; if (nativeJdbcExtractor != null) { rsToUse = nativeJdbcExtractor.getNativeResultSet(rs); } return rse.extractData(rsToUse); } finally { JdbcUtils.closeResultSet(rs); if (pss instanceof ParameterDisposer) { ((ParameterDisposer) pss).cleanupParameters(); } } } }); }

(2)Scala的Loan Pattern

package persia.demoobject FileLoan {  def main(args: Array[String]): Unit = {     import java.io._          /**      * Execute Around Method 模式的一个变体就是Loan模式      * 如果想确保非内存资源得到确定性的释放,就可以使用这个模式      * 可以这样认为这种资源密集型的对象是接给你的,用过之后应该立即归还。      */     def writeToFile(fname: String)(codeBlock: PrintWriter => Unit)={         val writer = new PrintWriter(new File(fname))         try{            codeBlock(writer)         }finally{            writer.close()         }     }          writeToFile("/home/scipio/output.txt"){        writer => writer write "hello from scala"     }  }}

    其实,Loan Pattern是 Execute Around Method模式的变种。

package persia.demoobject ExecuteAround {  /**   *  将类的构造函数标记为private,这样就不会在这个类或它的半生对象之外创建出类的实例   *  这样只能以确定的方式使用对象,从而保证了其行为是按照确定的方式自动执行   */   class Resource private(){    println("starting transaction...")    private def cleanUp(){ println("ending transaction.")}    def op1 = println("operation 1")    def op2 = println("operation 2")    def op3 = println("operation 3")      }  object Resource{     def use(codeBlock: Resource => Unit){        val res = new Resource        try{           codeBlock(res)        }finally{           res.cleanUp()        }     }  }  def main(args: Array[String]): Unit = {     Resource.use{ res =>        res.op1        res.op2        res.op3     }  }}

转载于:https://my.oschina.net/scipio/blog/282232

你可能感兴趣的文章
Fragment的使用
查看>>
快速排序
查看>>
程序员面试题100题第09题——查找链表中倒数第K个结点
查看>>
132. Palindrome Partitioning II
查看>>
WCF批量打开服务
查看>>
Python脚本运行出现语法错误:IndentationError:unexpected indent
查看>>
ios开发--KVO浅析
查看>>
【Android】6.3 ProgressDialog
查看>>
Ecshop删除no_license点击查看 云登陆失败,您未有license
查看>>
ecshop模板标签的预定义变量
查看>>
php模板引擎技术简单实现
查看>>
转 Android中this、super的区别
查看>>
MySQL 报错ERROR 1054 (42S22): Unknown column 'plugin' in 'mysql.user'
查看>>
安装虚拟机,磁盘选择厚置备延迟置零与厚置备置零和Thin Provision有什么区别...
查看>>
微信小程序--问题汇总及详解之form表单
查看>>
debian wget 报ERROR: The certificate of ‘xxx’ is not trusted.
查看>>
jQuery 获取和设置radio 和 checkbox 值的操作
查看>>
XMLSpy 生成xml模板(转)
查看>>
指定屏幕区域截图
查看>>
php连接数据的步骤
查看>>