Template method mode of handwritten JdbcTemplate

Template method pattern

Template method pattern, also known as template pattern, refers to the framework that defines an algorithm in operation and delays some steps to subclasses. The subclass can redefine some specific steps of the algorithm without changing the structure of the algorithm, which belongs to behavioral design pattern.

The template method pattern actually encapsulates a fixed process, which is composed of several steps. The specific steps can be implemented by subclasses, so that the fixed process can produce different results. The essence of template method is to abstract and encapsulate the process, and then inherit and implement the class.

General UML class diagram

Examples

We usually cook at home, (1) buy vegetables, (2) wash vegetables, (3) cook, (4) eat, (5) wash dishes if we have time, and wash them tomorrow if we don't have time. These five steps are the process of the defined algorithm; Then you need to buy different materials for different dishes and wash different materials. The practice is also different. This needs to be implemented by subclasses. Then we want to make some fine-tuning for the algorithm whose parent class has been defined, that is, through rewriting and hook methods.

First, define a cooking algorithm and an abstract class DodishTemplate. There is no difference between eating and washing dishes. It has been implemented. Buying, washing and cooking are different according to different cooking methods, which need to be implemented by the subclass itself. Step 5: wash the dishes. haveTime is the hook method. Whether there is time is up to the subclass to consider.

public abstract class DodishTemplate {
    /**
     * The process of cooking
     */
    public final void dodish() {
        //1. Buy vegetables
        preparation();

        //2. Wash vegetables
        washVegetables();

        //3. Cook
        doing();

        //4. Eat
        eatting();

        //5. Wash the dishes
        if (haveTime()) {
            washDishes();
        }
    }

    protected abstract void preparation();

    protected abstract void washVegetables();

    protected abstract void doing();

    protected void eatting() {
        System.out.println("having dinner");
    }

    //Hook Method 
    protected abstract boolean haveTime();

    protected void washDishes() {
        System.out.println("Wash the dishes");
    }

}

Implement EggsWithTomato, a tomato fried egg class. Buy vegetables, wash vegetables and cook. Have you had time to implement all the subclasses? The last one likes to eat very much, so rewrite the parent class's meal.

/**
 * Scrambled Eggs with Tomato
 */
public class EggsWithTomato extends DodishTemplate {

    @Override
    protected void preparation() {
        System.out.println("Buy tomatoes and eggs");
    }

    @Override
    protected void washVegetables() {
        System.out.println("Wash tomatoes and eggs");
    }

    @Override
    protected void doing() {
        System.out.println("Make scrambled eggs with tomatoes");
    }

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

    //rewrite
    @Override
    protected void eatting() {
        System.out.println("I had a good time");
    }

}

Implement a braised meat redbraidmeat, buy vegetables, wash vegetables and cook. Has there been time for subclasses to be implemented

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

    @Override
    protected void washVegetables() {
        System.out.println("Wash meat");
    }

    @Override
    protected void doing() {
        System.out.println("Make braised meat");
    }

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

Finally, write a test class to test it

public class Test {
    public static void main(String[] args) {
        System.out.println("=========Process of making tomatoes and eggs=========");
        EggsWithTomato eggsWithTomato = new EggsWithTomato();
        eggsWithTomato.dodish();

        System.out.println("=========Braised pork in brown sauce=========");
        RedBraisedMeat redBraisedMeat = new RedBraisedMeat();
        redBraisedMeat.dodish();
    }
}

This is the result. The template method pattern includes abstract methods, concrete methods and hook methods. Therefore, hooks can be differentiated through implementation and rewriting.

Handwritten JDBC

Create a template class JdbcTemplate to encapsulate all JDBC operations. Take a query as an example. The data structure returned will be different with different tables in each query. Different data structures should be encapsulated into different entity objects, and the logic of each entity encapsulation is different, but the processing flow before and after encapsulation is unchanged. Therefore, we can use the template method pattern to design such a business scenario.

Create an abstract class JdbcTemplate that encapsulates all processes:

public abstract class JdbcTemplate {

    private DataSource dataSource;

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

    public final List<?> executeQuery(String sql, Object[] values) {
        try {
            //1. Get connection
            Connection conn = this.getConnection();
            //2. Create statement set
            PreparedStatement pre = this.createPrepareStatement(conn, sql);
            //3. Execute statement set
            ResultSet rs = this.executeQuery(pre, values);
            //4. Processing result set
            List<Object> result = new ArrayList<>();
            while (rs.next()) {
                result.add(rowMapper(rs));
            }
            //5. Close result set
            rs.close();
            //6. Close statement set
            pre.close();
            //7. Close connection
            conn.close();
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

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

    //This is not allowed to be rewritten
    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();
    }

    //This is not allowed to be rewritten
    private PreparedStatement createPrepareStatement(Connection conn, String sql) throws SQLException {
        return conn.prepareStatement(sql);
    }

    //This is not allowed to be rewritten
    private Connection getConnection() throws SQLException {
        return this.dataSource.getConnection();
    }

}

Create entity object Member class:

@Data
public class Member {

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

}

Create database operation class 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;
    }

}

Client test code:

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

Advantages and disadvantages

advantage:

  1. Using the template method to put the code with the same processing logic into the abstract parent class can improve the reusability of the code.
  2. Add different codes into different subclasses, and add new behaviors through the extension of subclasses to improve the scalability of codes.
  3. The invariable behavior is written on the parent class and the repeated code of the child class is removed, which provides a good code reuse platform and conforms to the opening and closing principle.

Disadvantages:

  1. As the number of classes increases, each abstract class needs a subclass to implement, resulting in an increase in the number of classes.
  2. The increase of the number of classes indirectly increases the complexity of the system.
  3. The inheritance relationship has its own shortcomings. If a new abstract method is added to the parent class, all subclasses must be changed.

Source code of this article and other design patterns: https://github.com/xuhaoj/pattern-demo

Tags: Java Scala JDBC Design Pattern Algorithm

Posted on Mon, 06 Sep 2021 15:15:08 -0400 by Marchingknight11