Backend Development 12 min read

Template Method Design Pattern in Java: Theory, Implementation, and Framework Applications

This article explains the Template Method design pattern, illustrating its algorithm skeleton and step customization with Java code examples, and demonstrates real‑world applications in Spring, MyBatis, and other backend frameworks, highlighting advantages, drawbacks, and practical implementation details.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Template Method Design Pattern in Java: Theory, Implementation, and Framework Applications

Overview – The Template Method pattern defines an algorithm skeleton while allowing subclasses to override specific steps without changing the overall structure.

Use Cases – Analogies such as tea‑making illustrate how the fixed steps (boiling water, brewing, drinking) map to a generic process, while the variable steps (type of tea, brewing time) are left to subclasses.

API Development Scenario – Typical API handling consists of four steps: parse request parameters, validate parameters, process business logic, and assemble response data.

Payment Order Scenario – Payment processing also follows three fixed steps: construct request to bank/third‑party, initiate payment, and handle the result.

Algorithm Class (Abstract Template)

package com.tian.springbootdemo.controller;
import com.tian.springbootdemo.rep.Result;
/**
 * @auther: 老田
 * @Description: 模板类
 */
public abstract class AbstractTemplate {
    /**
     * Algorithm skeleton
     */
    public Result execute() {
        // step 1: parse parameters
        parseRequestParameters();
        // step 2: validate parameters
        checkRequestParameters();
        // step 3: business processing
        Object data = doBusiness();
        // step 4: assemble response
        return assembleResponseParameters(data);
    }
    public abstract void parseRequestParameters();
    public abstract void checkRequestParameters();
    public abstract Object doBusiness();
    public abstract Result assembleResponseParameters(Object object);
}

Implementation Class 1 – MyApiController

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: 老田
 * @Description: api接口
 */
@RequestMapping("/api")
@Controller
public class MyApiController extends AbstractTemplate {
    @RequestMapping(value = "/users", method = RequestMethod.POST)
    @ResponseBody
    @Override
    public Result execute() {
        return super.execute();
    }
    @Override
    public void parseRequestParameters() {
        System.out.println("*****解析参数*****");
    }
    @Override
    public void checkRequestParameters() {
        System.out.println("*****校验参数*****");
    }
    @Override
    public Object doBusiness() {
        System.out.println("*****处理业务*****");
        User user = new User();
        user.setName("小田哥");
        user.setId(1);
        user.setAge(20);
        user.setSex("man");
        return user;
    }
    @Override
    public Result assembleResponseParameters(Object object) {
        System.out.println("*****返回参数*****");
        Result result = new Result("200", "处理成功");
        result.setData(object);
        return result;
    }
}

Implementation Class 2 – LoginController

import com.tian.springbootdemo.dao.domain.User;
import com.tian.springbootdemo.rep.Result;
import org.springframework.web.bind.annotation.*;
/**
 * @auther: 老田
 * @Description: api接口
 */
@RequestMapping("/api")
@RestController
public class LoginController extends AbstractTemplate {
    @PostMapping(value = "/login")
    @Override
    public Result execute() {
        return super.execute();
    }
    @Override
    public void parseRequestParameters() {
        System.out.println("解析登录参数");
    }
    @Override
    public void checkRequestParameters() {
        System.out.println("校验登录用户名是否为空,密码是否为空");
    }
    @Override
    public Object doBusiness() {
        System.out.println("通过用户名查询是否存在此用户");
        System.out.println("校验用户密码是否正确");
        System.out.println("登录成功");
        User user = new User();
        user.setName("小田哥");
        user.setId(1);
        user.setAge(20);
        user.setSex("man");
        return user;
    }
    @Override
    public Result assembleResponseParameters(Object object) {
        System.out.println("*****返回参数*****");
        Result result = new Result("200", "登录成功");
        result.setData(object);
        return result;
    }
}

Related Classes

public class Result {
    // response code
    private String responseCode;
    // description
    private String message;
    // data
    private Object data;
    // constructors, getters, setters omitted for brevity
}
public class User implements Serializable {
    private Integer id;
    private String name;
    private String sex;
    private int age;
    // constructors, getters, setters omitted for brevity
}

Testing – The article shows how to use IDEA’s REST Client to invoke the API endpoints and view console output.

Advantages

Improves code reuse by placing common logic in the abstract class.

Enhances extensibility; different behaviors are added via concrete subclasses.

Enables inverse control: the parent class drives subclass operations.

Disadvantages

Introduces additional subclasses, increasing the number of classes and overall system complexity.

Framework Applications

Spring – The AbstractApplicationContext.refresh() method is a classic template method that orchestrates container startup steps.

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        prepareRefresh();
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        prepareBeanFactory(beanFactory);
        try {
            postProcessBeanFactory(beanFactory);
            invokeBeanFactoryPostProcessors(beanFactory);
            registerBeanPostProcessors(beanFactory);
            initMessageSource();
            initApplicationEventMulticaster();
            onRefresh();
            registerListeners();
            finishBeanFactoryInitialization(beanFactory);
            finishRefresh();
        }
    }
}

MyBatis – The BaseExecutor.update() method defines the template, delegating the actual update logic to doUpdate() in subclasses such as SimpleExecutor and ReuseExecutor .

@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.");
    }
    clearLocalCache();
    return doUpdate(ms, parameter);
}

Both frameworks illustrate how the Template Method pattern provides a stable algorithm structure while allowing extensible, domain‑specific behavior.

Conclusion – The Template Method pattern defines an algorithm skeleton and lets subclasses implement specific steps; it is widely used in Spring, MyBatis, Dubbo and other backend frameworks, offering reusable, extensible code that is valuable for interview discussions.

Javabackend-developmentSpringMyBatisDesign Patterntemplate method
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.