The template method pattern has a lot of applications in Sring. In general, we will use the template method to delegate the current implementation to subclasses to improve the extensibility and reusability of the code. Because parent-child relationships are involved, the template method pattern is implemented based on inheritance. The template method pattern is a behavioral pattern.

To put it simply, the skeleton of the algorithm is defined by the parent class, and the methods and the order in which they are called are specified, while the specific methods are implemented by the child class.

Let’s do a little demo; Let’s take blogging as an example. The general steps of blogging are as follows:

  • Open target website
  • Open the editor
  • Write an article
  • Published articles

The sample code

The first step is to define a parent class and provide a template method.

package com.glmapper.designmode.mudolmethod;
/ * * *@descriptionAbstract template parent *@email: <a href="[email protected]"></a>
 * @author: lei uncle *@date: 18/4/30 * /
public abstract class AbstractTemplateMethod {
    /** * process method 1: abstract method for subclass implementation */
    public abstract void openTargetWebSite(a);

    /** * process method 2: Subclasses have the option to override */
    public void openMarkDown(a){
        System.out.println("Open editor");
    }

    /** * process method 3: abstract method for subclass implementation */
    public abstract void writeBlog(a);

    /** * process method 4: Subclasses have the option to override */
    protected void publisher(a){
        System.out.println("Post an article");
    }

    /** * the template method, declared final here, does not want subclasses to override this method to prevent changes to the process execution order */
    public final void templateWriteBlog(a){ openTargetWebSite(); openMarkDown(); writeBlog(); publisher(); }}Copy the code

The above code provides a templateWriteBlog method that includes some of the flow of blogging. Some of these process methods have a default implementation provided by their parent class, while some of the different methods are implemented by subclasses.

package com.glmapper.designmode.mudolmethod;
/ * * *@description: * subclass@email: <a href="[email protected]"></a>
 * @author: lei uncle *@date: 18/4/30 * /
public class JueJinTemplateMethodPolicy extends AbstractTemplateMethod {
    @Override
    public void openTargetWebSite(a) {
        System.out.println("Go to the gold digger website.");
    }

    @Override
    public void writeBlog(a) {
        System.out.println("Write a Spring-related article"); }}Copy the code

Subclasses 1: JueJinTemplateMethodPolicy, this subclass implements part of the parent class method, including: openTargetWebSite and writeBlog. (In general, it will not override the default method of the parent class, only the abstract method reserved in the parent class to achieve).

package com.glmapper.designmode.mudolmethod;

/ * * *@description: * subclass@email: <a href="[email protected]"></a>
 * @author: lei uncle *@date: 18/4/30 * /
public class CSDNTemplateMethodPolicy extends AbstractTemplateMethod{

    @Override
    public void openTargetWebSite(a) {
        System.out.println("Go to the CSDN website");
    }

    @Override
    public void writeBlog(a) {
        System.out.println("Write an article on design patterns."); }}Copy the code

Subclass 2: CSDNTemplateMethodPolicy, actually the function of the subclass and subclass 1 is the same, just provides another implementation strategy; (In many cases, the template method pattern is used in conjunction with the policy pattern, using a template mechanism to implement different functions through different policies for parts of the process in the template.)

package com.glmapper.designmode.mudolmethod;
/ * * *@description: * subclass@email: <a href="[email protected]"></a>
 * @author: lei uncle *@date: 18/4/30 * /
public class MainTest {
    public static void main(String[] args) {
        AbstractTemplateMethod csdnTemplate = new CSDNTemplateMethodPolicy();
        csdnTemplate.templateWriteBlog();

        AbstractTemplateMethod juejinTemplate = newJueJinTemplateMethodPolicy(); juejinTemplate.templateWriteBlog(); }} Open the CSDN website, open the editor, and write a design pattern article. Open the Nuggets website, open the editor, and write a Spring-related articleCopy the code

Above is the client code and the output. It is clear from the output that some methods in the template will be deferred to subclasses. The template method allows subclasses to redefine specific steps of an algorithm without changing the structure of the algorithm. So for the template method pattern, the parent class is always in control of the process, while the child class only helps the parent class implement some customizable steps.

Mode analysis

Take a look at the class diagram for the template method pattern:

As you can see from the class diagram, the roles in the template method pattern are also very simple, consisting of two main roles:

  • AbstractTemplate:

    • Define one or more abstract operations for subclasses to implement. These abstract actions are the basic actions in the process (corresponding to a specific action method in the template method); These basic operations are the constituent steps of a top-level logic
    • A template method is defined and implemented. The template method is typically a concrete method that provides a skeleton of top-level logic, the component steps of which are deferred to subclasses in the corresponding abstraction. Of course, some of the methods in this top-level logic can also be implemented by default by the parent class.
  • Concrete class (SubTemplateImpl) :

    • Implements one or more abstract methods defined by the parent class
    • Each abstract template role can have any number of concrete template roles corresponding to it, and each concrete template role can give different implementations of these abstract methods.

The concept of this method in the template method is broken down into two kinds, one is the template method, and one is the basic method in the template method. The template method defines the rules of the game, and the basic method implements each part of the rules.

The advantages of the template approach are obvious. It can help us effectively solve the following scenarios:

  • Encapsulate invariant parts and extend variable parts.
  • Extract common code for easy maintenance.
  • The behavior is controlled by the parent class and implemented by the child class.

However, the disadvantages are also obvious, because for each different implementation, a subclass is required to implement, resulting in an increase in the number of classes, making the system larger.

Application of the typical template method pattern

The first thing that comes to mind is servlets, and the life cycle of servlets.

  • Initialize the init
  • To deal with the service
  • Destroy destroy

In fact, I think this is also a representation of the template method, although there is no top-level template method defined in the servlet to control the process (my idea is that the process is controlled by the container, or perhaps by default).

There are default implementations of init and destroy in its subclass GenericServlet, and the Service method is left to subclasses, meaning that any servlet class must implement the Service method.

The service method here is a template method. The service method responds to the client by calling one or more of the seven DO methods that need to be provided by a concrete subclass of HttpServlet.

Implementation in HttpServlet:

protected void service(HttpServletRequest req, HttpServletResponse
resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince =
                req.getDateHeader("If-Modified-Since");
                if (ifModifiedSince < lastModified) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304); }}}else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg =
            lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg); }}Copy the code

Implementation in FrameworkServlet (FrameworkServlet is the parent of SpringMVC core controller DispatchServlet) :

/** * Override the parent class implementation in order to intercept PATCH requests. */
@Override
protected void service(HttpServletRequest request,
HttpServletResponse response)
		throws ServletException, IOException {

	HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
	if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
		processRequest(request, response);
	}
	else {
		super.service(request, response); }}Copy the code

So much for learning about the template method pattern. May 1 happy!!