设计模式----模板设计模式

模板模式概念

  • 什么是模板模式

模板模式又叫做模板方法模式,它是指定义一个算法的骨架,并允许子类为一个或者多个步骤提供实现,简单理解:在实际开发中,如果一段相同的代码在项目中多次重复使用,可以将算法封装到一个模板方法中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。

模板模式事例

  • 用事例代码解释模板模式

比如:周末和对象约上去看电影,有如下步骤:网上订票、去电影院、取票、找座位、看电影,以上都是必要的步骤,这里定义一个非必要步骤,是否购买爆米花的步骤;今天想吃爆米花就买,相反就不买。下面就这个例子进行编写事例代码。

1)定义一个抽象类

public abstract class SeeMovie {
    /**
     * 定义看电影的方法
     */
    protected final void see(){
        //1、网上订票
        this.buyTicket();

        //2、去电影院
        this.go();

        //3、取票
        this.takeTicket();

        //4、找座位
        this.findSeat();

        //5、观看电影
        this.enjoyMovie();

        //6、购买爆米花
        this.buyPopcorn();
    }

    final void buyTicket(){
        System.out.println("购买电影票");
    }

    final void go(){
        System.out.println("去电影院");
    }

    final void takeTicket(){
        System.out.println("取电影票");
    }

    final void findSeat(){
        System.out.println("寻找座位");
    }

    final void enjoyMovie(){
        System.out.println("欣赏电影");
    }

    //购买爆米花,可选方法
    abstract void buyPopcorn();
}

2)定义张三看电影的类,继承SeeMovie抽象类

public class ZhangSanSeeMovie extends SeeMovie{
    //重写钩子方法
    @Override
    void buyPopcorn() {
        System.out.println("看电影当然要吃爆米花,才有灵魂");
    }
}

3)定义李四看电影的类,继承SeeMovie抽象类

public class LiSiSeeMovie extends SeeMovie{
    @Override
    void buyPopcorn() {
        System.out.println("今天肚子好撑,吃不下爆米花了");
    }
}

4)测试类

public class SeeMovieTest {
    public static void main(String[] args) {
        System.out.println("***张三看电影***");
        SeeMovie zhangsanSee = new ZhangSanSeeMovie();
        zhangsanSee.see();

        System.out.println("***张李四看电影***");
        SeeMovie lisiSee = new LiSiSeeMovie();
        lisiSee.see();
    }
}

5)测试结果

image-20210617223912207

  • 事例代码及结果分析

在上述事例中,可以发现,看电影基本是固定的流程,去看电影都需要经历必要的步骤,那么将其抽取成模板类即可,比如上述代码中的SeeMovie抽象类,如果在众多方法中,需要子类可以自定义的方法,可以定义为钩子方法,比如上述事例中的buyPopcorn方法,那么子类可以根据自己的需求进行重写即可。这种就是典型的模板模式。

从JDBC中学习模板模式

  • 说明

以jdbc执行查询为例,原生的jdbc类操作,基本步骤都需要经历,注册驱动、创建连接、发送sql指令、获取结果集和关闭连接的操作,下面就针对原生jdbc的查询为例,学习模板模式

1)定义一个顶层的mapper接口,用于ORM映射

public interface Mapper<T> {
    T mapRow(ResultSet rs,int rowNum) throws Exception;
}

2)定义JDBC的操作模板,上面已经说明,模板模式最重要的类

public abstract class JdbcTemplate {
    //定义数据源
    private DataSource dataSource;

    //构造方法初始化数据源
    public JdbcTemplate(DataSource dataSource){
        this.dataSource = dataSource;
    }

    public List<?> executeQuery(String sql,Mapper mapper,Object[] values){
        try {
            //1、获取连接
            Connection connection = this.getConnection();

            //2、创建预编译对象
            PreparedStatement ps = this.createPreparedStatement(connection,sql);

            //3、执行sql语句,并获取语句集
            ResultSet resultSet = this.executeQuery(ps,values);

            //4、处理结果集
            List<?> result = this.parseResultSet(resultSet,mapper);

            //5、关闭结果集
            this.closeResultSet(resultSet);

            //6、关闭预编译对象
            this.closeStatement(ps);

            //7、关闭连接
            this.closeConnection(connection);

            //8、返回结果
            return result;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    //创建连接方法
    protected Connection getConnection() throws Exception{
        return this.dataSource.getConnection();
    }

    //获取预编译对象方法
    protected PreparedStatement createPreparedStatement(Connection connection,String sql) throws Exception {
        return connection.prepareStatement(sql);
    }

    //执行sql语句,并获取结果集的方法,子类只需要重写此方法即可
    protected ResultSet executeQuery(PreparedStatement ps,Object[] values) throws Exception{
        for(int i = 0;null != values && i < values.length;i++){
            ps.setObject(i,values[i]);
        }
        return ps.executeQuery();
    }

    //处理结果集的方法
    protected List<?> parseResultSet(ResultSet resultSet,Mapper mapper) throws Exception{
        List<Object> result = new ArrayList<Object>();
        //迭代结果集
        int rowNum = 1;
        while(resultSet.next()){
            result.add(mapper.mapRow(resultSet,rowNum++));
        }
        return result;
    }

    //关闭结果集方法
    protected void closeResultSet(ResultSet resultSet) throws Exception{
        if(resultSet != null){
            resultSet.close();
        }
    }

    //关闭预编译对象方法
    protected void closeStatement(PreparedStatement ps) throws Exception{
        if(ps != null){
            ps.close();
        }
    }

    //关闭连接方法
    protected void closeConnection(Connection connection)throws Exception{
        if(connection != null){
            connection.close();
        }
    }
}

3)定义Person类的model,用于后续测试

public class Person {
    private int id;
    private String name;
    private String password;
	//为了减少文章篇幅,这里get和set方法及toString方法省略,也可以使用lombok实现
}

4)编写PersonDao实现类,这个类属于JdbcTemplate的子类,需要继承,并重写executeQuery方法

public class PersonDao extends JdbcTemplate{
    public PersonDao(DataSource dataSource) {
        super(dataSource);
    }

    //重写父类查询的方法
    public List<?> selectAll(){
        String sql = "select id,name,password from t_person";
        return super.executeQuery(sql,new Mapper<Person>(){
            public Person mapRow(ResultSet rs, int rowNum) throws Exception {
                //定义实体类
                Person person = new Person();
                person.setId(rs.getInt("id"));
                person.setName(rs.getString("name"));
                person.setPassword(rs.getString("password"));
                return person;
            }
        },null);
    }
}

5)测试类

public class Test {
    public static void main(String[] args) throws Exception{
        //这里引入了druid获取数据源dataSource
        Properties properties = new Properties();
        InputStream in = Test.class.getClassLoader().getResourceAsStream("db.properties");
        properties.load(in);
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);

        //执行查询操作
        PersonDao personDao = new PersonDao(dataSource);
        List<Person> personList = (List<Person>) personDao.selectAll();

        //迭代
        ListIterator<Person> it = personList.listIterator();
        while(it.hasNext()){
            Person person = it.next();
            System.out.println(person);
        }
    }
}

6)测试结果

image-20210617235728205

  • 总结

在jdbc操作中,从JdbcTemplate模板类中,就可以看出模板模式的核心了,将子类都必须使用的方法,在父类中进行实现执行,如果需要子类执行特定的方法,可以由子类重写即可。比如这个事例中的executeQuery方法。

源码及sql脚本地址:链接:https://pan.baidu.com/s/1goL-TBr22e50Ywsp4pF1fg 提取码:irib

以上就是设计模式中的模板设计模式!!!

关注公众号:源码说