模板方法模式(Template Method)
概述:
定义一个操作中的算法的骨架, 而将一些步骤延迟到子类中。 Template Method 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
例如生产饮料的流程:加原料、加水、烧水、加工、混合。现在我们向针对加原料来写一些算法,但是不能影响整个流程结构,就可以用到模板方法模式。
使用场景分析:
Template Method 模式一般是需要继承的。 这里想要探讨另一种对 Template Method 的理解。
Spring中的 JdbcTemplate, 在用这个类时并不想去继承这个类, 因为这个类的方法太多, 但是我们还是想用到 JdbcTemplate 已有的稳定的、 公用的数据库连接, 那么我们怎么办呢?
我们可以把变化的东西抽出来作为一个参数传入 JdbcTemplate 的方法中。 但是变化的东西是一段代码, 而且这段代码会用到JdbcTemplate 中的变量。 怎么办?
那我们就用回调对象吧。 在这个回调对象中定义一个操纵JdbcTemplate 中变量的方法, 我们去实现这个方法, 就把变化的东西集中到这里了。 然后我们再传入这个回调对象到 JdbcTemplate, 从而完成了调用。
这就是 Template Method 不需要继承的另一种实现方式。
public class JdbcTemplate {
private DataSource dataSource;
public JdbcTemplate(DataSource dataSource){
this.dataSource = dataSource;
}
private Connection getConnection() throws Exception{
return this.dataSource.getConnection();
}
private PreparedStatement createPreparedStatement(Connection conn,String sql) throws Exception{
return conn.prepareStatement(sql);
}
private ResultSet executeQuery(PreparedStatement pstmt,Object [] values) throws Exception{
for (int i = 0; i <values.length; i ++){
pstmt.setObject(i,values[i]);
}
return pstmt.executeQuery();
}
private void closeResultSet(ResultSet rs) throws Exception{
rs.close();
}
private void closeStatement(Statement stmt) throws Exception{
stmt.close();
}
private void closeConnection(Connection conn) throws Exception{
//通常把它放到连接池回收
}
private List<?> parseResultSet(ResultSet rs,RowMapper rowMapper) throws Exception{
List<Object> result = new ArrayList<Object>();
int rowNum = 1;
while (rs.next()){
result.add(rowMapper.mapRow(rs,rowNum ++));
}
return result;
}
public List<?> executeQuery(String sql,RowMapper<?> rowMapper,Object [] values){
try {
//1、获取连接
Connection conn = this.getConnection();
//2、创建语句集
PreparedStatement pstmt = this.createPreparedStatement(conn,sql);
//3、执行语句集,并且获得结果集
ResultSet rs = this.executeQuery(pstmt,values);
//4、解析语句集
List<?> result = this.parseResultSet(rs,rowMapper);
//5、关闭结果集
this.closeResultSet(rs);
//6、关闭语句集
this.closeStatement(pstmt);
//7、关闭连接
this.closeConnection(conn);
return result;
}catch (Exception e){
e.printStackTrace();
return null;
}
}
}
public interface RowMapper<T> {
public T mapRow(ResultSet rs, int rowNum) throws Exception;
}
public class MemberDao {
//为什么不继承,主要是为了解耦
private JdbcTemplate JdbcTemplate = new JdbcTemplate(null);
public List<?> query(){
String sql = "select * from t_member";
return JdbcTemplate.executeQuery(sql,new RowMapper<Member>(){
@Override
public Member mapRow(ResultSet rs, int rowNum) throws Exception {
Member member = new Member();
member.setUsername(rs.getString("username"));
member.setPassword(rs.getString("password"));
member.setAge(rs.getInt("age"));
member.setAddr(rs.getString("addr"));
return member;
}
},null);
}
}
上述代码中就是模拟出真实使用JdbcTemplate的场景,我们只需要实现RowMapper接口就可以完成解析ResultSet的实际场景,又可以调用整个Jdbc流程。
策略模式模板模式对比
- 策略模式:只有选择权(有用户自己选择已有的固定算法)
- 模板模式:侧重的点不是选择,因为没得选择,你必须这么做,你可以参与某一部分内容自定义。
设计模式从来都是组合使用,你中有我,我中有你。