1959 字
约 6 分钟
1
模板设计模式(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://www.clxhxhhr.top/posts/379/ 评论
0 条
还没有评论,先写一条吧。