An overview of the

The template pattern is to define an algorithm skeleton in an operation and then defer some steps to subclasses. The template method allows subclasses to redefine certain steps of an algorithm without changing its structure.

Click here: a 100,000-word interview cheat sheet

Usage scenarios

Tea water

We all know that the basic steps of tea making (algorithm skeleton) are as follows:

Boil water, make tea, drink tea water.

The key step in the whole process is to make tea. What kind of tea does it take to make tea? How long is the bubble? Leave it to subclasses to implement.

API

Those of you who have written an API know that writing an API generally involves four steps:

Parameter analysis, parameter verification, business processing, organization to return parameters.

The request parameters are parsed into the request parameters of the business JSON parsed into entity classes; Parameter verification: You can use the general method to check whether the parameter is null, or you can define a special verification method. Generally, each interface is not the same when dealing with business, and it is basically implemented by itself. As for the return parameters, you may have to return them according to the API interface business.

Payment order

Those who have done payment related systems know that payment orders can be roughly divided into three steps:

The organization requests the request parameters of the bank or the third-party payment company, initiates the payment, and processes the return result.

The steps in the above three scenarios are the skeleton of the algorithm. As for each step, everyone may have different preferences for tea drinking, API interface services, and payment processing of banks or third-party payment, special processing may be required.

Scene reality

Implement an API interface

Algorithm class
package com.tian.springbootdemo.controller;
import com.tian.springbootdemo.rep.Result;
/ * * *@auther: Mr. Tian *@Description: template class */
public abstract class AbstractTemplate {

    /** * algorithm skeleton */
    public Result execute(a) {
        // Step 1: Parse the parameters
        parseRequestParameters();
        // Step 2: Verify parameters
        checkRequestParameters();
        // Step 3: Business processing
        Object data= doBusiness();
        // Step 4: Organize returns parameters
        return assembleResponseParameters(data);
    }

    /** * parses parameters */
    public abstract void parseRequestParameters(a);

    /** ** Check parameters */
    public abstract void checkRequestParameters(a);

    /** ** Business processing */
    public abstract Object doBusiness(a);

    /** * the organization returns the argument */
    public abstract Result assembleResponseParameters(Object object);
}

Copy the code
The implementation class a
import com.tian.springbootdemo.rep.Result;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/ * * *@auther: Mr. Tian *@Description: API interface */
@RequestMapping("/api")
@Controller
public class MyApiController extends AbstractTemplate {

    @RequestMapping(value = "/users", method = RequestMethod.POST)
    @ResponseBody
    @Override
    public Result execute(a) {
        return super.execute();
    }

    @Override
    public void parseRequestParameters(a) {
        System.out.println("***** resolve parameters *****");
    }

    @Override
    public void checkRequestParameters(a) {
        System.out.println("***** Check parameter *****");
    }

    @Override
    public Object doBusiness(a) {
        System.out.println("***** handle business *****");
        // TODO:Call service to process services
        User user = new User();
        user.setName("Brother Tammy");
        user.setId(1);
        user.setAge(20);
        user.setSex("man");
        return user;
    }

    @Override
    public Result assembleResponseParameters(Object object) {
        System.out.println("***** return parameter *****");
        Result result = new Result("200"."Processed successfully");
        result.setData(object);
        returnresult; }}Copy the code
The implementation class two
import com.tian.springbootdemo.dao.domain.User;
import com.tian.springbootdemo.rep.Result;
import org.springframework.web.bind.annotation.*;

/ * * *@auther: Mr. Tian *@Description: API interface */
@RequestMapping("/api")
@RestController
public class LoginController extends AbstractTemplate {
    @PostMapping(value = "/login")
    @Override
    public Result execute(a) {
        return super.execute();
    }
    @Override
    public void parseRequestParameters(a) {
        System.out.println("Resolve login parameters");
    }

    @Override
    public void checkRequestParameters(a) {
        System.out.println("Verify login username is null and password is null.");
    }

    @Override
    public Object doBusiness(a) {
        System.out.println("Query the existence of this user by username");
        System.out.println("Verify user password");
        System.out.println("Login successful");
        User user = new User();
        user.setName("Brother Tammy");
        user.setId(1);
        user.setAge(20);
        user.setSex("man");
        return user;
    }

    @Override
    public Result assembleResponseParameters(Object object) {
        System.out.println("***** return parameter *****");
        Result result = new Result("200"."Login successful");
        result.setData(object);
        returnresult; }}Copy the code
Related classes
/ * * *@auther: Mr. Tian *@Description: Returns information */
public class Result {
    / / return code
    private String responseCode;
    / / description
    private String message;
    / / data
    private Object data;

    public Result(a) {}public Result(String responseCode, String message) {
        this.responseCode = responseCode;
        this.message = message;
    }

    public Result(String responseCode, String message, Object data) {
        this.responseCode = responseCode;
        this.message = message;
        this.data = data;
    }

    public String getResponseCode(a) {
        return responseCode;
    }

    public void setResponseCode(String responseCode) {
        this.responseCode = responseCode;
    }

    public String getMessage(a) {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getData(a) {
        return data;
    }

    public void setData(Object data) {
        this.data = data; }}Copy the code
import java.io.Serializable;

/ * * *@auther: Mr. Tian *@Description: * / data
public class User implements Serializable {
    //id
    private Integer id;
    // User name
    private String name;
    / / gender
    private String sex;
    / / age
    private int age;

    public User(a) {}public User(Integer id, String name, String sex, int age) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    public Integer getId(a) {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName(a) {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex(a) {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge(a) {
        return age;
    }

    public void setAge(int age) {
        this.age = age; }}Copy the code
test

Here the REST Client under the Tools of IDEA is used for interface testing:

enter image description here

enter image description here

Take a look at the Console Console print:

enter image description here

enter image description here

This allows us to apply the template design pattern to our concrete code, as well as to the implementation classes of other apis.

In AbstractTemplate, an argument validation method can be implemented in default mode, such as null, but subclasses can override this method and do their own special validation. For example, if there is a mobile phone number in the parameter, we not only verify that the mobile phone number is empty, but also verify that the mobile phone number is 11 digits, is valid, and so on.

Advantages and disadvantages of the template pattern

advantages
  • Improve code reuse by putting the same parts of code into abstract classes;

  • Improve extensibility, put different into different implementation classes, by implementing the extension of the class to increase some of their own needs;

  • Reverse control is achieved by invoking a parent class to implement the operations of the class, and by extending the implementation class to add new behavior.

disadvantages
  • Because of the introduction of abstract classes, each different implementation needs a subclass to be realistic, which leads to an increase in the number of classes, resulting in implementation complexity.

How do the big guys use it in the frame?

In the Spring

AbstractApplicationContext refreash method is in the template method, the source code for:

@Override
public void refresh(a) throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) { 
            // Call the container ready to refresh method, get the container at that time,
            // Set the synchronization flag for the container
            prepareRefresh();
            // Tell subclasses to start refreshBeanFactory(),
            // The Bean defines the load slave of the resource file
            // The refreshBeanFactory() method of the subclass starts
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            // Configure container features for BeanFactory, such as class loaders, event handlers, and so on
            prepareBeanFactory(beanFactory);
            try { 
                // Specify special BeanPost event handlers for some subclasses of the container
                //----- subclass implementation
                postProcessBeanFactory(beanFactory);
                // Invoke all registered BeanFactoryPostProcessor beans
                invokeBeanFactoryPostProcessors(beanFactory);
                // Register the BeanPost event handler for the BeanFactory.
                //BeanPostProcessor is the Bean post-processor,
                // Listen for events triggered by the container
                registerBeanPostProcessors(beanFactory);
                // Initializes the information source, which is related to internationalization.
                initMessageSource();
                // Initialize the container event propagator.
                initApplicationEventMulticaster();
                // Call some special Bean initializer of the subclass
                //----- subclass implementation
                onRefresh();
                // Register event listeners for event propagators.
                registerListeners();
                // Initialize all remaining singleton beans
                finishBeanFactoryInitialization(beanFactory);
                // Initialize the container's lifecycle event handler,
                // And publish the container's lifecycle events
                finishRefresh();
                / /...

Copy the code

This method is the context launch template method. This is one of the scenarios where the template pattern is used in Spring.

The Mybatis

The Update method in BaseExecutor is a template method

 / * * * SqlSession. Update/insert/delete template method this method is called * * /
    @Override
    public int update(MappedStatement ms, Object parameter) throws SQLException {
         ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
        if (closed) {
            throw new ExecutorException("Executor was closed.");
        }
        // Update the local cache by subclass.
        // Template method pattern
        clearLocalCache();
        // Implemented by subclasses (hook methods)
        return doUpdate(ms, parameter);
    }

Copy the code

In BaseExecutor only methods are defined, but the implementation is in subclasses

/ / update
protected abstract int doUpdate(MappedStatement ms, Object parameter)
                                                     throws SQLException;
/ / query
protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
                   throws SQLException;
 / /... Methods that start with do are left to specific subclasses to implement

Copy the code

The BaseExecutor implementation class is as follows:

enter image description here

Realization of doUpdate method in SimpleExecutor class

@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      Create a new StatementHandler
      // ResultHandler is passed null
      StatementHandler handler = configuration.newStatementHandler(
          this, ms, parameter,          RowBounds.DEFAULT, null.null);
      // Prepare statements
      stmt = prepareStatement(handler, ms.getStatementLog());
      //StatementHandler.update
      return handler.update(stmt);
    } finally{ closeStatement(stmt); }}Copy the code

Implementation of class ReuseExecutor doUpdate method

@Override
  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Configuration configuration = ms.getConfiguration();
     // Like SimpleExecutor,
     Create a new StatementHandler
     // ResultHandler is passed null
     StatementHandler handler = configuration.newStatementHandler(
             this, ms, parameter,       RowBounds.DEFAULT, null.null);
     // Prepare statements
     Statement stmt = prepareStatement(handler, ms.getStatementLog());
     return handler.update(stmt);
  }

Copy the code

This is a classic application of the template method pattern in Mybatis.

conclusion

The template method pattern defines an algorithm skeleton, and then each implementation class implements its own business logic. There are good implementation cases in Spring, Mybatis, Dubbo and other frameworks. Relatively speaking, the template method mode is relatively simple, in the interview and the interviewer can talk for a while.

“For the better of the future, what is bitter now?”