Understand the hook method and template method. It's enough to read this article

This article is excerpted from "design patterns should be learned this way"

In the common template method pattern, an abstract method will be designed and given to its subclass implementation. This method is called template method. The hook method is an empty implementation of the abstract method or the method defined in the interface, and it is also an implementation of the template method pattern.

1 hook method in template mode

We take the online course creation process as an example: Publishing preview materials → making courseware PPT → live online broadcast → submitting class notes → submitting source code → arranging homework → checking homework. First create the abastractsource abstract class.

public abstract class AbastractCourse {
    
    public final void createCourse(){
        //1. Release preview materials
        postPreResoucse();
        
        //2. Making courseware PPT
        createPPT();
        
        //3. Live broadcast online
        liveVideo();
        
        //4. Upload after class materials
        postResource();
        
        //5. Assignment
        postHomework();
        
        if(needCheckHomework()){
            checkHomework();
        }
    }

    protected abstract void checkHomework();

    //Hook Method 
    protected boolean needCheckHomework(){return  false;}

    protected void postHomework(){
        System.out.println("Assign homework");
    }

    protected void postResource(){
        System.out.println("Upload after class materials");
    }

    protected void liveVideo(){
        System.out.println("Live teaching");
    }

    protected void createPPT(){
        System.out.println("Making courseware");
    }

    protected void postPreResoucse(){
        System.out.println("Release preview materials");
    }

}

Copy code

There is a hook method in the above code, which may not be understood by some small partners. The author will explain it here. The main purpose of designing hook method is to intervene the execution process, so as to make the control behavior process more flexible and more in line with the actual business needs. The return value of hook methods is generally the return value suitable for conditional branch statements (such as boolean, int, etc.). Partners can decide whether to use the hook method according to their business scenarios. Then create the JavaCourse class.

public class JavaCourse extends AbastractCourse {
    private boolean needCheckHomework = false;

    public void setNeedCheckHomework(boolean needCheckHomework) {
        this.needCheckHomework = needCheckHomework;
    }

    @Override
    protected boolean needCheckHomework() {
        return this.needCheckHomework;
    }

    protected void checkHomework() {
        System.out.println("inspect Java task");
    }
}

Copy code

Create the python course class.

public class PythonCourse extends AbastractCourse {
    protected void checkHomework() {
        System.out.println("inspect Python task");
    }
}

Copy code

Finally, write the client test code.

    public static void main(String[] args) {
        System.out.println("=========Architect course=========");
        JavaCourse java = new JavaCourse();
        java.setNeedCheckHomework(false);
        java.createCourse();


        System.out.println("=========Python curriculum=========");
        PythonCourse python = new PythonCourse();
        python.createCourse();
    }
		
Copy code

Through such a case, I believe the partners have a basic impression of the template method mode. In order to deepen our understanding, we will introduce a common business scenario.

2. Reconstruct JDBC business operation using template method pattern

Create a template class JdbcTemplate to encapsulate all JDBC operations. Take a query as an example. The tables in each query are different, and the returned data structure is also different. Different data should be encapsulated into different entity objects. The logic of each entity encapsulation is different, but the processing flow before and after encapsulation is unchanged. Therefore, the template method pattern can be used to design such a business scenario. First, create an interface RowMapper that constrains ORM logic.

/**
 * ORM Mapping customized interfaces
 * Created by Tom.
 */
public interface RowMapper<T> {
    T mapRow(ResultSet rs,int rowNum) throws Exception;
}

Copy code

Then create an abstract class JdbcTemplate that encapsulates all processing flows.

public abstract class JdbcTemplate {
    private DataSource dataSource;

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

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

    private List<?> parseResultSet(ResultSet rs, RowMapper<?> rowMapper) throws Exception {
        List<Object> result = new ArrayList<Object>();
        int rowNum = 0;
        while (rs.next()){
            result.add(rowMapper.mapRow(rs,rowNum++));
        }
        return result;
    }


    private ResultSet executeQuery(PreparedStatement pstm, Object[] values) throws SQLException {
        for (int i = 0; i < values.length; i++) {
            pstm.setObject(i,values[i]);
        }
        return pstm.executeQuery();
    }

    private PreparedStatement createPrepareStatement(Connection conn, String sql) throws SQLException {
        return conn.prepareStatement(sql);
    }

    private Connection getConnection() throws SQLException {
        return this.dataSource.getConnection();
    }
}

Copy code

Create an entity object Member class.

public class Member {

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }
}

Copy code

Create the 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, new RowMapper<Member>() {
            public Member mapRow(ResultSet rs, int rowNum) throws Exception {
                Member member = new Member();
                //Too many fields, prototype mode
                member.setUsername(rs.getString("username"));
                member.setPassword(rs.getString("password"));
                member.setAge(rs.getInt("age"));
                member.setAddr(rs.getString("addr"));
                return member;
            }
        },null);
    }
}

Copy code

Finally, write the client test code.

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

Copy code

It is hoped that through the business scenario analysis of these two cases, the partners can have a deeper understanding of the template method pattern.

Added by R0CKY on Mon, 08 Nov 2021 03:53:41 +0200