Template method pattern

A Template Method Pattern, also known as a Template Pattern, is a framework that defines an algorithm in an operation, deferring some steps to subclasses. It makes it possible for subclasses to redefine some specific steps of the algorithm without changing the structure of the algorithm, which belongs to behavioral design pattern.

The template method pattern essentially encapsulates a fixed process that consists of several steps that can be implemented differently by subclasses to produce different results from the fixed process. The essence of the template approach is to abstract and encapsulate the process and then implement the class inheritance.

Generic UML class diagrams

For example

We usually cook at home by ourselves. (1) buy food, (2) wash food, (3) cook food, (4) eat food, (5) wash dishes if we have time, and do them tomorrow if we have no time. These five steps are the process of the defined algorithm. Then, to make different dishes, we need to buy different materials, wash different materials, and do different things. This needs to be realized by subclasses. And then we want to do some tweaks to the algorithms that have been defined by the superclass, by overwriting and hook methods.

First define a cooking algorithm, define an abstract class DodishTemplate, eating and washing dishes are no different, already implemented, buy dishes, wash dishes, cook dishes according to different dishes are different, need to subclass to implement. Step 5 Wash the bowl haveTime this is the hook method, in the end there is no time by subclass to consider.

public abstract class DodishTemplate {
    /** * The process of cooking */
    public final void dodish(a) {
        / / 1, to buy food
        preparation();

        / / 2, wash the dishes
        washVegetables();

        / / 3, do the dishes
        doing();

        / / 4, to eat
        eatting();

        / / 5, washing the dishes
        if(haveTime()) { washDishes(); }}protected abstract void preparation(a);

    protected abstract void washVegetables(a);

    protected abstract void doing(a);

    protected void eatting(a) {
        System.out.println("Eat");
    }

    // Hook method
    protected abstract boolean haveTime(a);

    protected void washDishes(a) {
        System.out.println("Washing the dishes"); }}Copy the code

Implementation of a tomato fried eggs EggsWithTomato, buy vegetables wash vegetables do dishes, there is no time subclasses have been implemented, the last one eat very like to eat, so rewrite the parent class eat.

/** ** Scrambled eggs with tomatoes */
public class EggsWithTomato extends DodishTemplate {

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

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

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

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

    / / rewrite
    @Override
    protected void eatting(a) {
        System.out.println("I had fun eating."); }}Copy the code

To achieve a RedBraisedMeat, buy vegetables, wash vegetables and cook vegetables, there is no time subclasses have been implemented

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

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

    @Override
    protected void doing(a) {
        System.out.println("Make braised pork in brown sauce.");
    }

    @Override
    protected boolean haveTime(a) {
        return true; }}Copy the code

Finally, write a test class to test it

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

        System.out.println("========= process for making braised pork in brown sauce =========");
        RedBraisedMeat redBraisedMeat = newRedBraisedMeat(); redBraisedMeat.dodish(); }}Copy the code

This is the result, contained in the template method patternAbstract methods, concrete methods, and hook methods, so throughImplementation, rewrite, hookDifferentiation can be achieved.

Handwritten JDBC

Create a template class, JdbcTemplate, that encapsulates all JDBC operations. Take a query as an example. The data structure returned varies depending on the table used for each query. For different data structures, we need to encapsulate them into different entity objects, and the logic of each entity is different, but the processing process before and after encapsulation remains unchanged. Therefore, we can use the template method pattern to design such a business scenario.

Create an abstract JdbcTemplate class that encapsulates all the processes:

public abstract class JdbcTemplate {

    private DataSource dataSource;

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

    public finalList<? > executeQuery(String sql, Object[] values) {try {
            // get the connection
            Connection conn = this.getConnection();
            // create a statement set
            PreparedStatement pre = this.createPrepareStatement(conn, sql);
            //3. Execute statement set
            ResultSet rs = this.executeQuery(pre, values);
            //4
            List<Object> result = new ArrayList<>();
            while (rs.next()) {
                result.add(rowMapper(rs));
            }
            // close the result set
            rs.close();
            // close the statement set
            pre.close();
            // Close the connection
            conn.close();
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    / / implementation
    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(a) throws SQLException {
        return this.dataSource.getConnection(); }}Copy the code

Create entity object Member class:

@Data
public class Member {

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

}
Copy the code

Create database action class MemberDao:

public class MemberDao extends JdbcTemplate {

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

    publicList<? > 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"));
        returnmember; }}Copy the code

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);
    }
}
Copy the code

The advantages and disadvantages

Advantages:

  1. Using template methods to put code with the same processing logic into an abstract parent class improves code reuse.
  2. Different code in different subclasses, through the extension of the subclass to add new behavior, improve the extensibility of the code.
  3. The unchanging behavior is written on the parent class, removing the duplicate code of the subclass, providing a good platform for code reuse, in accordance with the open and closed principle.

Disadvantages:

  1. An increase in the number of classes, each abstract class requires a subclass to implement, resulting in an increase in the number of classes.
  2. The increase in the number of classes indirectly increases the complexity of the system.
  3. Inheritance has its own disadvantages. If the parent class adds a new abstract method, all subclasses have to change it.

Source code for this article and other design patterns: github.com/xuhaoj/patt…