模板模式又名模板方法模式。
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method 使得子类可以不改变 一个算法的结构即可重定义该算法的某些特定步骤。 TemplateMethod 模式一般是需要继承的。
和策略模式对比:
策略模式:只有选择权(由用户自己选择已有的固定算法)
模板模式:侧重点不是选择,你没有选择,你必须这么做,你可以参与某一部分内容自定义
1. 采用 普通的抽象方法实现
通过Java中得JdbcTemplate例子来解析
1)实体类:
package com.vison.template.dao;
public class Member {
private String userName;
private String password;
private int age;
...get set 方法省略
}
2)JdbcTemplate定义为抽象类,使用模板方法
package com.vison.template;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
public abstract class JdbcTemplate {
private DataSource dataSource;
public JdbcTemplate(DataSource dataSource){
this.dataSource=dataSource;
}
public List<Object> executeQuery(String sql , Object[] values) throws Exception{
//创建连接
Connection connection = dataSource.getConnection();
//创建语句集
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//执行语句集,返回结果集
ResultSet resultSet = preparedStatement.executeQuery();
//解析结果集
List<Object> result = new ArrayList<Object>();
while (resultSet.next()){
result.add(processResultSet(resultSet));
}
//List<?> result = this.processResultSet(resultSet);
//关闭结果集连接
resultSet.close();
//关闭语句集连接
preparedStatement.close();
//回收数据库连接
connection.close();
//返回结果
return result;
}
//模板方法
public abstract Object processResultSet(ResultSet rs) throws Exception;
}
3) JdbcTemplate 子类 MemberDAO ,重写模板方法
package com.vison.template.dao;
import com.vison.template.JdbcTemplate;
import javax.sql.DataSource;
import java.sql.ResultSet;
import java.util.List;
public class MemberDAO extends JdbcTemplate {
public MemberDAO(DataSource dataSource){
super(dataSource);
}
public List<Object> query(String sql, Object[] values)throws Exception{
return super.executeQuery(sql,values);
}
//重写模板方法,可以定义多个子类,来自定义实现这个方法的设置
@Override
public Object processResultSet(ResultSet rs) throws Exception {
Member member = new Member();
member.setUserName(rs.getString("userName"));
member.setPassword(rs.getString("password"));
member.setAge(rs.getInt("age"));
return member;
}
}
4) 测试
package com.vison.template;
import com.vison.template.dao.MemberDAO;
import java.util.List;
public class TestJdbcTemplate {
public static void main(String[] args) throws Exception {
MemberDAO memberDAO = new MemberDAO(null);
String sql = "select * from t_user";
List<Object> result = memberDAO.query(sql, null);
}
}
2. 采用接口的方式实现
上面通过继承的方式来实现模板方法的重写,这里可以采用组合的方式;抽象方法可以用接口来实现。
这种方式采用匿名内部类来实现,就可以减少子类的新建,而且采用组合方式也解耦。优化代码如下
如下:
1) 同样的Member实体类
2) 新建一个接口RowMapper
package com.vison.template.dao;
import java.sql.ResultSet;
import java.util.List;
public interface RowMapper<T> {
T processResult (ResultSet resultSet) throws Exception;
}
3) JdbcTemplate改写
package com.vison.template;
import com.vison.template.dao.RowMapper;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class JdbcTemplate {
private DataSource dataSource;
public JdbcTemplate(DataSource dataSource){
this.dataSource=dataSource;
}
//这里传进一个RowMapper接口更灵活使用
public List<Object> executeQuery(RowMapper rowMapper,String sql , Object[] values) throws Exception{
//创建连接
Connection connection = this.getConnection();
//创建语句集
PreparedStatement preparedStatement = this.getPreparedStatement(sql, connection);
//执行语句集,返回结果集
ResultSet resultSet = this.getResultSet(preparedStatement);
//解析结果集
List<Object> result = this.parseResultSet(rowMapper, resultSet);
//关闭结果集连接
this.resultSetClose(resultSet);
//关闭语句集连接
this.preparedStatementClose(preparedStatement);
//使用连接池 回收数据库连接
this.connClose(connection);
//返回结果
return result;
}
private void connClose(Connection connection) throws SQLException {
connection.close();
}
private void preparedStatementClose(PreparedStatement preparedStatement) throws SQLException {
preparedStatement.close();
}
private void resultSetClose(ResultSet resultSet) throws SQLException {
resultSet.close();
}
private List<Object> parseResultSet(RowMapper rowMapper, ResultSet resultSet) throws Exception {
List<Object> result = new ArrayList<Object>();
while (resultSet.next()){
result.add(rowMapper.processResult(resultSet));
}
return result;
}
private ResultSet getResultSet(PreparedStatement preparedStatement) throws SQLException {
return preparedStatement.executeQuery();
}
private PreparedStatement getPreparedStatement(String sql, Connection connection) throws SQLException {
return connection.prepareStatement(sql);
}
private Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
4) 改写MemberDAO,组合方式
package com.vison.template.dao;
import com.vison.template.JdbcTemplate;
import javax.sql.DataSource;
import java.sql.ResultSet;
import java.util.List;
public class MemberDAO {
private DataSource dataSource;
private JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
public MemberDAO(DataSource dataSource){
this.dataSource = dataSource;
}
public List<Object> query(String sql, Object[] values)throws Exception{
//这里用匿名内部类来实现,就不用每次新建一个模板方法的实现类
return jdbcTemplate.executeQuery(new RowMapper<Member>() {
public Member processResult(ResultSet rs) throws Exception {
Member member = new Member();
member.setUserName(rs.getString("userName"));
member.setPassword(rs.getString("password"));
member.setAge(rs.getInt("age"));
return member;
}
},sql,values);
}
}