手写JdbcTemplate的模板方法模式

模板方法模式

模板方法模式(Template Method Pattern)又叫模板模式,是指定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤,属于行为型设计模式。

模板方法模式实际上是封装了一个固定流程,该流程由几个步骤组成,具体步骤可以由子类进行不同的实现,从而让固定的流程产生不同的结果。模板方法的本质就是抽象封装流程,然后进行类的继承实现。

通用UML类图

image.png

举例说明

我们平时在家自己做饭, (1)买菜,(2)洗菜, (3)做菜,(4)吃饭,(5)有时间的话洗碗,没时间的话就放到明天再洗,这五步就是定义的算法的流程;然后做不同菜需要买不同的材料,洗不同的材料,做法也不一样,这个就需要子类去具体实现。然后对于父类已经定义好的算法我们想做一些微调,那就是通过重写钩子方法

先定义一个做饭的算法,定义一个抽象类DodishTemplate,吃饭和洗碗没啥区别,已经实现好了,买菜,洗菜,做菜根据不同的菜做法是不一样的,需要子类自己去实现。第五步洗碗 haveTime 这个就是钩子方法,到底有没有时间由子类自己去考虑。

public abstract class DodishTemplate {
    /**
     * 做饭的过程
     */
    public final void dodish() {
        //1、买菜
        preparation();

        //2、洗菜
        washVegetables();

        //3、做菜
        doing();

        //4、吃饭
        eatting();

        //5、洗碗
        if (haveTime()) {
            washDishes();
        }
    }

    protected abstract void preparation();

    protected abstract void washVegetables();

    protected abstract void doing();

    protected void eatting() {
        System.out.println("吃饭");
    }

    //钩子方法
    protected abstract boolean haveTime();

    protected void washDishes() {
        System.out.println("洗碗");
    }

}

实现一个西红柿炒蛋类EggsWithTomato,买菜洗菜做菜,有没有时间子类都已经实现了,最后一个吃饭很喜欢吃,所以重写了父类的吃饭。

/**
 * 西红柿炒蛋
 */
public class EggsWithTomato extends DodishTemplate {

    @Override
    protected void preparation() {
        System.out.println("买西红柿和鸡蛋");
    }

    @Override
    protected void washVegetables() {
        System.out.println("洗西红柿和鸡蛋");
    }

    @Override
    protected void doing() {
        System.out.println("做西红柿炒蛋");
    }

    @Override
    protected boolean haveTime() {
        return false;
    }

    //重写
    @Override
    protected void eatting() {
        System.out.println("吃的很开心");
    }

}

实现一个红烧肉类RedBraisedMeat,买菜洗菜做菜,有没有时间子类都已经实现了

public class RedBraisedMeat extends DodishTemplate {
    @Override
    protected void preparation() {
        System.out.println("买肉");
    }

    @Override
    protected void washVegetables() {
        System.out.println("洗肉");
    }

    @Override
    protected void doing() {
        System.out.println("做红烧肉");
    }

    @Override
    protected boolean haveTime() {
        return true;
    }
}

最后写个测试类测试一下

public class Test {
    public static void main(String[] args) {
        System.out.println("=========做西红柿鸡蛋流程=========");
        EggsWithTomato eggsWithTomato = new EggsWithTomato();
        eggsWithTomato.dodish();

        System.out.println("=========做红烧肉流程=========");
        RedBraisedMeat redBraisedMeat = new RedBraisedMeat();
        redBraisedMeat.dodish();
    }
}

这个就是结果,在模板方法模式中,包含了抽象方法、具体方法和钩子方法,所以通过实现,重写,钩子可以达到差异化。
image.png

手写JDBC

创建一个模板类JdbcTemplate,封装所有的JDBC操作。以查询为例,每次查询的表不同,返回的数据结构也就不一样。我们针对不同的数据结构,都要封装成不同的实体对象,而每个实体封装的逻辑都是不一样的,但封装前和封装后的处理流程是不变的。因此,我们可以使用模板方法模式来设计这样的业务场景。

创建封装了所以处理流程的抽象类JdbcTemplate:

public abstract class JdbcTemplate {

    private DataSource dataSource;

    public JdbcTemplate(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public final List<?> executeQuery(String sql, Object[] values) {
        try {
            //1、获取连接
            Connection conn = this.getConnection();
            //2、创建语句集
            PreparedStatement pre = this.createPrepareStatement(conn, sql);
            //3、执行语句集
            ResultSet rs = this.executeQuery(pre, values);
            //4、处理结果集
            List<Object> result = new ArrayList<>();
            while (rs.next()) {
                result.add(rowMapper(rs));
            }
            //5、关闭结果集
            rs.close();
            //6、关闭语句集
            pre.close();
            //7、关闭连接
            conn.close();
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //实现
    protected abstract Object rowMapper(ResultSet rs) throws SQLException;

    //这个是不让重写的
    private ResultSet executeQuery(PreparedStatement pre, Object[] values) throws SQLException {
        for (int i = 0; i < values.length; i++) {
            pre.setObject(i, values[i]);
        }
        return pre.executeQuery();
    }

    //这个是不让重写的
    private PreparedStatement createPrepareStatement(Connection conn, String sql) throws SQLException {
        return conn.prepareStatement(sql);
    }

    //这个是不让重写的
    private Connection getConnection() throws SQLException {
        return this.dataSource.getConnection();
    }

}

创建实体对象Member类:

@Data
public class Member {

    private String username;
    private String password;
    private String nickname;
    private int age;
    private String addr;

}

创建数据库操作类MemberDao:

public class MemberDao extends JdbcTemplate {

    public MemberDao(DataSource dataSource) {
        super(dataSource);
    }

    public List<?> selectAll() {
        String sql = "select * from t_member";
        return super.executeQuery(sql, null);
    }

    @Override
    protected Object rowMapper(ResultSet rs) throws SQLException {
        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;
    }

}

客户端测试代码:

public class Test {
    public static void main(String[] args) {
        MemberDao memberDao = new MemberDao(null);
        List<?> result = memberDao.selectAll();
        System.out.println(result);
    }
}

优缺点

优点:

  1. 利用模板方法将相同处理逻辑的代码放到抽象父类中,可以提高代码的复用性。
  2. 将不同的代码不同的子类中,通过对子类的扩展增加新的行为,提高代码的扩展性。
  3. 把不变的行为写在父类上,去除子类的重复代码,提供了一个很好的代码复用平台,符合开闭原则。

缺点:

  1. 类数目的增加,每一个抽象类都需要一个子类来实现,这样导致类的个数增加。
  2. 类数量的增加,间接地增加了系统的复杂度。
  3. 继承关系自身缺点,如果父类添加新的抽象方法,所有子类都要改一遍。

本文及其他设计模式源码:https://github.com/xuhaoj/pattern-demo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值