模板方法模式
模板方式模式也是比较好理解的设计模式之一,结合实际例子理解,在饮料实际制作过程中,大体上会分为如下几个大的步骤:1、加原料,2、烧水,3、加水,4、加工,5、混合。无非就是这几个步骤,但是针对第一步和第四步中加入的原料和工序不同,也会产生不同的饮料。其实这就是模板模式的一种类型。下面给出模板模式的官方介绍——定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构,即可重定义该算法的结果。其结构图异常的简单如下所示:
Spring中常用的JdbcTemplate,其中用到了模板模式,但是如果想要理解模板模式,这个利用JdbcTemplate显得有点大才小用,这里还是用一个比较简单的实例来理解模板模式。
实例类图如下:比较好理解,这里就不赘述了
其中的DrinkProduce算是提供了一个模板,其中addOrginal方法和makeDrink方法都是抽象的方法,其实现交给了子类MilkProduce和CoffeeProduce来完成。client是测试类。下面给出每一个类的代码
DrinkProduce
public abstract class DrinkProduce {
//第一步:加原料
public abstract void addOrginal();
//第二步:加水
public void addWater(){
System.out.println("第二步:加水");
}
//第三步:烧水
public void boilWater(){
System.out.println("第三步:烧水");
}
//第四步:加工
public abstract void makeDrink();
//第五步:混合
public void getDrink(){
this.addOrginal();
this.addWater();
this.boilWater();
this.makeDrink();
System.out.println("第五步:混合,包装,完成操作");
}
}
MikeProduce
public class MilkProduce extends DrinkProduce{
@Override
public void addOrginal() {
System.out.println("加牛奶");
}
@Override
public void makeDrink() {
System.out.println("萃取,提纯,杀菌");
}
}
CoffeeProduce
public class CoffeeProduce extends DrinkProduce{
@Override
public void addOrginal() {
System.out.println("加咖啡豆");
}
@Override
public void makeDrink() {
System.out.println("将煮好的咖啡,打上奶泡,拉花");
}
}
Client 测试类:
public class Client {
public static void main(String[] args) {
DrinkProduce milkProduce = new MilkProduce();
DrinkProduce coffeeProduce = new CoffeeProduce();
milkProduce.getDrink();
coffeeProduce.getDrink();
}
}
运行结果如下:
应用场景
当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑模板方法模式来处理。
其实模板模式只是在一定程度上完成了解耦的操作,当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。我们通过模板方法模式把这些行文搬移到单一的地方(就是提取公有部分,抽象成抽象方法),这样就帮助子类摆脱重复的不变行为的纠缠。(出自大话设计模式)
再回到之前所说的,Spring中的JdbcTemplate也用到了模板模式,其实在一定程度上,针对数据库的访问操作也就是固定的几步,这里以查询为例来说明:
一般访问数据库,获取查询结果集的操作步骤如下所示:针对其中标红的,就需要进行抽象,因为不同的语句,获取的结果集不同。如果不只是单独讨论查询操作,其中执行并获取结果集的操作也有所不同。
这里就模拟一下实现一个简易的JdbcTemplate
public abstract class JdbcTemplate {
private DataSource dataSource;
public JdbcTemplate(DataSource dataSource){
this.dataSource = dataSource;
}
private Connection getConnection() throws Exception{
return this.getConnection();
}
private PreparedStatement createPreparedStatement(Connection connection,String sql) throws Exception{
return connection.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 closeStatement(Statement stmt) throws Exception{
stmt.close();
}
private void closeResultSet(ResultSet rs) throws Exception{
rs.close();
}
private void closeConnection(Connection connection) 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(processResultSet(rs,rowNum++));
}
return result;
}
public List<Object> executeQuery(String sql,RowMapper<?> rowMapper,Object[] values){
try {
//-----这个是操作数据库的一般流程
//1.获取连接
Connection connection = dataSource.getConnection();
//2.创建语句集
PreparedStatement pstmt = connection.prepareStatement(sql);
//3.执行语句集并且获得结果集
ResultSet rs = pstmt.executeQuery();
//4.解析语句集
List<Object> result = new ArrayList<Object>();
int rowNum = 1;
while(rs.next()){
result.add(processResultSet(rs,rowNum++));
}
List<?> result=processResultSet(rs);
//5.关闭语句集
rs.close();
//6.关闭结果集
pstmt.close();
//7.关闭连接
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//这个是处理结果集,没法在这里实现,所以进行了抽象
public abstract Object processResultSet(ResultSet rs,int rowNum) throws SQLException;
}
模拟一个MemberDao
public class MemberDao extends JdbcTemplate{
//private JdbcTemplate jdbcTemplate = new JdbcTemplate(null);
public MemberDao(DataSource dataSource){
super(dataSource);
}
public List<Object> query(){
String sql = "select * from t_member"; this.processResultSet(rs,rowNum);
/*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.setAddr(rs.getString("addr"));
member.setAge(rs.getInt("age"));
member.setNicename(rs.getString("nickname"));
return member;
}
},null);*/
}
@Override
public Object processResultSet(ResultSet rs, int rowNum) throws SQLException {
Member member = new Member();
member.setUsername(rs.getString("username"));
member.setPassword(rs.getString("password"));
member.setAddr(rs.getString("addr"));
member.setAge(rs.getInt("age"));
member.setNicename(rs.getString("nickname"));
return member;
}
}
以上只是一个简易的JdbcTemplate实现实例,真实在开发过程中都是通过将JdbcTemplate注入到dao实例中,对结果集的映射也是交给RowMapper来完成,这个问题等到学习到源码的时候会有更加清晰的理解。