模板方法模式总结

模板方法模式

模板方式模式也是比较好理解的设计模式之一,结合实际例子理解,在饮料实际制作过程中,大体上会分为如下几个大的步骤: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来完成,这个问题等到学习到源码的时候会有更加清晰的理解。

猜你喜欢

转载自blog.csdn.net/liman65727/article/details/79717759