1959 字
约 6 分钟
2
模板设计模式(Template Method Pattern)

模板设计模式(Template Method Pattern)

1. 什么是模板设计模式?

模板设计模式是一种行为型设计模式

核心思想:

将一个算法流程固定下来,把其中可变化的步骤交给子类实现。

简单理解:

一个事情有固定流程:

上传文件

1. 校验文件大小
2. 校验文件类型
3. 上传文件
4. 记录日志

其中:

校验逻辑
日志逻辑

所有存储方式都一样。

但是:

上传文件

这个动作不同:

上传本地

上传服务器

上传OSS

所以:

模板模式就是:

父类定义流程

子类实现细节

2. 为什么需要模板设计模式?

2.1 没有模板模式的问题

假设现在有一个文件上传系统。

支持:

本地存储

服务器存储

OSS存储

代码可能:

class LocalStorage {


    public void upload(File file){

        // 校验文件大小
        if(file.length() > 20){

            throw new RuntimeException();
        }


        // 上传本地
        System.out.println("上传本地");

    }

}

服务器:

class ServerStorage {


    public void upload(File file){


        // 校验文件大小
        if(file.length() > 20){

            throw new RuntimeException();
        }


        // 上传服务器
        System.out.println("上传服务器");

    }

}

OSS:

class OSSStorage {


    public void upload(File file){


        // 校验文件大小
        if(file.length() > 20){

            throw new RuntimeException();
        }


        // 上传OSS
        System.out.println("上传OSS");

    }

}

发现问题:

三个类都有:

文件校验

重复代码。

如果以后增加:

文件类型校验

病毒检测

上传日志

每个类都需要修改。


3. 模板模式如何解决?

分析一下:

上传文件其实有固定流程:

upload()

   |
   |
   ↓

文件校验

   |
   |
   ↓

具体上传

其中:

文件校验所有存储都一样。

上传方式不同。

所以抽象:

AbstractStorage

        |
        |
-------------------

LocalStorage

ServerStorage

OSSStorage

父类负责:

流程控制
公共代码

子类负责:

变化部分

4. 模板模式 Demo

定义接口

public interface Storage {


    void upload(File file);


    Object download();


    void remove();

}

5. 抽象模板类

公共逻辑放这里:

public abstract class AbstractStorage 
        implements Storage {


    private long maxFileSize;


    public AbstractStorage(long maxFileSize){

        this.maxFileSize = maxFileSize;

    }


    // 公共校验逻辑
    protected void validateFileSize(File file){


        if(file.length() > maxFileSize){

            throw new RuntimeException(
                "文件超过限制"
            );

        }

    }



    // 模板方法
    @Override
    public void upload(File file){


        // 第一步:校验
        validateFileSize(file);


        // 第二步:执行上传
        uploadDetail(file);

    }



    // 留给子类实现
    protected abstract void uploadDetail(File file);


}

这里最重要:

upload()

就是模板方法。

它规定:

先校验

再上传

子类不能决定流程。


6. 子类实现不同步骤

本地存储

public class LocalStorage 
        extends AbstractStorage {


    public LocalStorage(long maxFileSize){

        super(maxFileSize);

    }


    @Override
    protected void uploadDetail(File file){

        System.out.println(
            "上传到本地"
        );

    }


    public Object download(){

        return null;

    }


    public void remove(){

    }

}

服务器存储

public class ServerStorage 
        extends AbstractStorage {


    public ServerStorage(long maxFileSize){

        super(maxFileSize);

    }


    @Override
    protected void uploadDetail(File file){

        System.out.println(
            "上传到服务器"
        );

    }

}

OSS存储

public class OSSStorage 
        extends AbstractStorage {


    public OSSStorage(long maxFileSize){

        super(maxFileSize);

    }


    @Override
    protected void uploadDetail(File file){

        System.out.println(
            "上传到OSS"
        );

    }

}

7. 使用

public class Main {


    public static void main(String[] args) {


        Storage storage =
            new OSSStorage(20);


        storage.upload(
            new File("test.txt")
        );

    }

}

执行:

文件校验

上传到OSS

调用方不需要关心:

校验怎么做

上传流程是什么

8. 模板模式解决什么问题?

总结三个核心价值。


① 算法复用

多个类:

都有:

校验

日志

异常处理

流程控制

这些代码不用重复写。

统一放父类。

例如:

AbstractStorage

    |
    |
    ↓

所有存储方式共享

② 避免代码重复

没有模板:

LocalStorage

校验

上传


OSSStorage

校验

上传


ServerStorage

校验

上传

大量重复。

模板:

AbstractStorage

校验

上传流程


子类

具体上传

③ 提供扩展能力

父类规定流程:

upload(){

    validate();

    uploadDetail();

}

新增:

FTP存储

只需要:

class FTPStorage 
extends AbstractStorage

实现:

uploadDetail()

不用修改父类。

符合:

开闭原则:对扩展开放,对修改关闭。


9. 什么时候使用模板模式?

判断标准:

条件1:多个类拥有相同流程

例如:

支付流程:

1. 参数校验

2. 风控检查

3. 支付

4. 记录日志


不同支付:

支付宝

微信

银行卡

流程一样。

支付方式不同。

适合模板。


条件2:流程固定,但是某些步骤变化

例如:

登录流程:

1. 获取用户信息

2. 校验密码

3. 创建token

4. 返回结果

不同登录:

账号密码登录

微信登录

Github登录

其中:

创建token

返回结果

流程一样。

具体认证方式不同。

适合模板。


10. Spring 中的模板模式

WebMvcConfigurer

Spring MVC:

public interface WebMvcConfigurer {


    default void addInterceptors(
        InterceptorRegistry registry
    ){

    }


    default void addCorsMappings(
        CorsRegistry registry
    ){

    }

}

为什么提供这个接口?

因为 Spring MVC 内部已经定义好了扩展流程。

例如:

启动Spring MVC

       |
       |
       ↓

读取配置

       |
       |
       ↓

调用用户实现的方法

       |
       |
       ↓

完成初始化

用户只需要:

@Configuration
class WebConfig 
implements WebMvcConfigurer{


    public void addInterceptors(
        InterceptorRegistry registry
    ){

        registry.addInterceptor(
            new LoginInterceptor()
        );

    }

}

Spring负责:

整体流程

用户负责:

新增配置

这就是模板模式的:

预留扩展点。


11. 重试组件中的模板模式

重试流程:

执行任务

    ↓

失败

    ↓

判断是否继续重试

    ↓

等待

    ↓

再次执行

这个流程基本固定。

但是:

不同用户可能需要:

失败通知

记录日志

统计次数

发送报警

所以:

框架定义:

RetryTemplate

       |
       |
       ↓

执行流程


用户实现:

RetryListener

       |
       ↓

beforeRetry()

afterRetry()

onError()

框架控制流程:

用户扩展行为。


12. 模板模式和策略模式区别

容易混淆。

模板模式:

关注:

流程固定

部分步骤变化

结构:

父类

固定流程

↓

子类实现步骤

例如:

文件上传流程

支付流程

订单流程


策略模式:

关注:

同一个行为

多种算法选择

结构:

接口

↓

多个实现

例如:

支付方式

优惠算法

负载均衡算法


简单区别:

模板:

我规定流程,你实现其中一步。

策略:

我不管流程,你选择一种方案。


13. 总结

模板设计模式核心:

父类定义算法骨架

子类实现变化步骤

解决:

  • 多个类重复代码
  • 公共流程复用
  • 固定流程扩展

使用场景:

  • 文件上传流程
  • Spring MVC 配置扩展
  • 数据库操作流程
  • 支付流程
  • 重试组件
  • 生命周期管理

一句话总结:

模板模式就是把不变的流程放在父类,把变化的步骤交给子类实现,在保证流程统一的同时提供扩展能力。

在实际框架源码中,模板模式非常常见:

Spring
MyBatis
RPC框架
任务调度框架
重试组件

很多“提供一个接口让用户实现,然后框架帮你调用”的设计,本质上就是模板模式。

模板设计模式(Template Method Pattern)
http://clxhxhhr.top/posts/379/
作者
clxstart
发布于
2026-09-01
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。