“This is my 25th day of the August Genwen Challenge.More challenges in August”

What is the template method pattern?

A Template Method Pattern is a framework that defines an algorithm in an operation, deferring some steps to subclasses. The behavior design pattern allows subclasses to redefine certain steps of an algorithm without changing its structure.

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 for the fixed process. It’s a very simple inheritance mechanism for classes, but it’s a very widely used pattern. The essence of the template method pattern is to abstract and encapsulate the process and implement it concretely.

Second, the application scenario of template method mode

When an operation concrete fixed process is completed, the abstract fixed process steps are handed over to subclasses for concrete implementation (fixed process, different implementation). The template method pattern is also common in our daily life.

For example, we usually handle the entry process to fill in the entry registration form -> print the resume -> copy education -> copy the ID card -> sign the labor contract -> establish the roster -> apply for the work card -> arrange the station and so on;

For example, we usually cook at home: wash the pot -> ignition -> hot pot -> oil -> raw materials -> stir -> seasoning -> out of the pot;

In another sketch, Zhao benshan asks Song Dandan, “How do you put an elephant in a refrigerator?” Song Dandan replied: “The first step: open the refrigerator, the second step: put the elephant into the refrigerator, the third step: close the refrigerator door.” Zhao benshan asked again: “How to put the giraffe in the refrigerator?” Song Dandan replied: “The first step: open the refrigerator door, the second step: take out the elephant, the third step: put the giraffe in, the fourth step: close the refrigerator door.”

The template method pattern is used in the following scenarios:

  1. Implement the invariant parts of an algorithm once and leave the mutable behavior to subclasses.
  2. Common behaviors in each subclass are extracted and grouped into a common parent class to avoid code duplication.

Roles involved in the template method pattern

Let’s start with the generic UML class diagram for the template method pattern:

From the UML class diagram, we can see that the template method pattern contains two main roles:

  1. AbstractClass: Abstract template class that defines a set of algorithm frameworks/processes.
  2. ConcreteClass: Concrete implementation class that implements some steps of an algorithm framework/process.

Four, template method mode business case

1. Hook methods in the template method pattern

We still take the course creation process as an example: release preview materials -> make PPT -> live broadcast online -> submit classroom notes -> submit source code -> assign homework -> check homework. First let’s create an AbstractCourse abstract class:

public abstract class AbstractCourse {

    public final void createCourse(a) {
        //1. Release preview materials
        postPreResource();

        //2. Make courseware
        createPPT();

        //3. Live lectures
        liveVideo();

        //4
        postResource();

        //5
        postHomework();

        if(needCheckHomework()) { checkHomework(); }}protected abstract void checkHomework(a);

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

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

    protected void postResource(a) {
        System.out.println("Upload your materials.");
    }

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

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

    protected void postPreResource(a) {
        System.out.println("Release of preview materials"); }}Copy the code

There is a hook method in the above code that some of you may not understand very well, so I will explain it here. The hook method is designed to intervene in the execution process, making our control behavior flow more flexible and more in line with the actual business needs. The return value of a hook method is typically the value that is appropriate for a conditional branch statement (Boolean, int, etc.). Friends can decide whether to use the hook method based on their business scenario.

Next create the JavaCourse class:

public class JavaCourse extends AbstractCourse {

    private boolean needCheckHomework = false;

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

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

    @Override
    protected void checkHomework(a) {
        System.out.println("Check the Java Job"); }}Copy the code

Create the PythonCourse class:

public class PythonCourse extends AbstractCourse {
    @Override
    protected void checkHomework(a) {
        System.out.println("Check the Python job"); }}Copy the code

Client test code:

public class Test {

    public static void main(String[] args) {
        System.out.println("=========== Architect Course ==========");
        JavaCourse javaCourse = new JavaCourse();
        javaCourse.setNeedCheckHomework(true);
        javaCourse.createCourse();

        System.out.println("= = = = = = = = = = = Python class = = = = = = = = = =");
        PythonCourse pythonCourse = newPythonCourse(); pythonCourse.createCourse(); }}Copy the code

The running results are as follows:

Through such a case, I believe that partners have a basic impression of the template method pattern.

2. Reconstruct JDBC operation service scenarios using the template method mode

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. We encapsulate different entity objects for different data. The logic that each entity encapsulates is different, but the process is the same before and after encapsulation, so we can use the template method pattern to design such a business scenario.

Create an interface RowMapper that constrains ORM logic:

public interface RowMapper<T> {

    T mapRow(ResultSet rs, int rowNum) throws Exception;
}
Copy the code

After creating the abstract JdbcTemplate class that encapsulates all the processing flow:

public abstract class JdbcTemplate<T> {

    private DataSource dataSource;

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

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

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

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

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

    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<Member> {

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

    public List<Member> selectAll(a) {
        String sql = "select * from t_member";
        return super.executeQuery(sql, new RowMapper<Member>() {
            @Override
            public Member mapRow(ResultSet rs, int rowNum) throws Exception {
                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; }},null); }}Copy the code

Client test code:

public class Test {

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

I hope that the business scenario analysis of these two cases can help partners have a deeper understanding of the template method mode.

Five, template method mode in the source code

Mybatis framework also has some classical applications, let’s look at the BaseExecutor class, it is a basic SQL execution class, implement most of the SQL execution logic, and then several methods to subclass customization complete, source code is as follows:

public abstract class BaseExecutor implements Executor {...protected abstract int doUpdate(MappedStatement ms, Object parameter)
      throws SQLException;

  protected abstract List<BatchResult> doFlushStatements(boolean isRollback)
      throws SQLException;

  protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      throws SQLException;

  protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)
      throws SQLException; . }Copy the code

Methods such as doUpdate, doFlushStatements, doQuery, and doQueryCursor are implemented by subclasses. What subclasses do BaseExecutor have? Let’s take a look at its class diagram:

Let’s take a look at SimpleExecutor’s doUpdate implementation:

public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null.null);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.update(stmt);
    } finally{ closeStatement(stmt); }}Copy the code

Compare BatchExecutor’s doUpdate implementation:

public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
    final Configuration configuration = ms.getConfiguration();
    final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null.null);
    final BoundSql boundSql = handler.getBoundSql();
    final String sql = boundSql.getSql();
    final Statement stmt;
    if (sql.equals(currentSql) && ms.equals(currentStatement)) {
      int last = statementList.size() - 1;
      stmt = statementList.get(last);
      applyTransactionTimeout(stmt);
        handler.parameterize(stmt);//fix Issues 322
      BatchResult batchResult = batchResultList.get(last);
      batchResult.addParameterObject(parameterObject);
    } else {
      Connection connection = getConnection(ms.getStatementLog());
      stmt = handler.prepare(connection, transaction.getTimeout());
      handler.parameterize(stmt); //fix Issues 322
      currentSql = sql;
      currentStatement = ms;
      statementList.add(stmt);
      batchResultList.add(new BatchResult(ms, sql, parameterObject));
    }
  // handler.parameterize(stmt);
    handler.batch(stmt);
    return BATCH_UPDATE_RETURN_VALUE;
  }
Copy the code

Six, the advantages and disadvantages of the template method mode

Advantages:

  1. Using template methods to put code with the same processing logic into an abstract parent class improves code reuse.
  2. Put different code into subclasses, and add new behavior by extending subclasses to improve code extensibility.
  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 implementation.
  3. Inheritance has its own disadvantages. If the parent class adds a new abstract method, all subclasses have to change it.

Template method mode is relatively simple, I believe that partners will be able to learn, but also be able to understand well, as long as the practice, more combined with business scenarios to think about problems, will be able to use the template method mode.

7. Friendship links

Design Patterns – Factory Patterns learning tour

Design Patterns – a learning tour of singleton patterns

Design Patterns – A learning journey of prototyping patterns

Design Patterns – Builder patterns learning tour

Design Patterns – Agent patterns learning tour

Design Patterns – A learning tour of facade patterns

Design Patterns – A learning tour of decorator patterns

Design Patterns – Enjoy yuan patterns learning journey

Design Patterns – A learning journey of composite patterns

Design Patterns – Adapter patterns learning journey

Design Patterns – Bridge patterns learning journey

Design Patterns – Delegation patterns learning journey

Welcome to follow the wechat public account (MarkZoe) to learn from and communicate with each other.