设计模式
模板方法模式
模板方法模式(Template Method Pattern) 是一种行为型设计模式。
简单来说,它在一个方法中定义了一个算法的骨架(步骤),而将一些步骤的具体实现延迟到子类中。这样,子类可以在不改变算法结构的情况下,重新定义算法中的某些特定步骤。
核心思想:封装不变,扩展可变
想象一下“冲泡饮料”的过程:
- 烧开水(相同)
- 冲泡原料(不同:咖啡或茶叶)
- 倒入杯子(相同)
- 添加调料(不同:加糖或加柠檬)
在这个场景中,烧水和倒水是“不变”的结构,而冲泡什么、加什么调料是“可变”的细节。
模式结构
抽象类(Abstract Class):定义算法骨架。包含:
- 模板方法:定义了算法的步骤(通常设为
final,防止子类修改骨架)。 - 抽象方法:由子类实现的具体逻辑。
- 钩子方法(Hook):默认不做事或提供默认实现,子类可以视情况重写,用来控制算法的流程。
- 模板方法:定义了算法的步骤(通常设为
具体实现类(Concrete Class):实现抽象类中的抽象方法,完成属于自己的特定逻辑。
代码示例:制作咖啡与茶
1 | // 抽象类:饮料机 |
优缺点分析
| 优点 | 缺点 |
|---|---|
| 代码复用:将公共代码提取到父类。 | 类数量增加:每个不同的实现都需要一个子类。 |
| 扩展性好:增加新逻辑只需增加子类,符合开闭原则。 | 逻辑受限:子类必须遵守父类的骨架,灵活性受限。 |
| 控制权集中:算法结构在父类中统一管理。 | 理解成本:如果继承层次过深,代码阅读会变困难。 |
实际应用场景
- Java Servlet:
HttpServlet中的service()方法定义了处理请求的流程,而doGet()、doPost()交由开发者实现。 - Spring 框架:各种
JdbcTemplate、RestTemplate也是该模式的变体应用。 - JUnit:测试框架中定义的
setUp()、tearDown()钩子方法。
你想看一个关于如何在实际 Spring 项目中应用模板方法模式(例如处理不同类型的支付回调)的具体案例吗?
Spring Boot 开发中常用的设计模式
Spring Boot 本身不是“为了用设计模式而用设计模式”,但它的核心能力(IoC、AOP、自动配置、扩展点 SPI)天然就以一批经典模式为基础。理解这些模式能帮助你:
- 更顺畅地读源码(知道扩展点在什么位置)
- 写出更易扩展的业务代码(减少 if/else 和硬编码)
- 正确使用框架能力(如事务、事件、过滤链、自动装配)
下面是 Spring Boot 开发中最常见、最实用的一组模式速览。
单例模式(Singleton)
核心:全局唯一实例,统一管理生命周期。
Spring 里的体现:
- 默认
Bean作用域就是singleton(一个ApplicationContext内单例) - 单例并不等于“线程安全”:单例 bean 经常是无状态的(stateless),以避免并发问题
常见实践:Service/Repository 作为单例 bean;把“请求相关状态”放到方法参数/局部变量,或使用
request作用域。
工厂方法 / 抽象工厂(Factory Method / Abstract Factory)
核心:把“创建对象”这件事封装起来,调用方只关心“拿到能用的对象”。
Spring 里的体现:
BeanFactory/ApplicationContext:从容器“获取对象”,你不直接new@Bean方法本质上就是工厂方法:框架调用你的方法来创建 beanFactoryBean<T>:把复杂对象创建逻辑封装到一个工厂 bean 中(比如代理对象、连接工厂等)
建造者模式(Builder)
核心:用链式调用逐步构建复杂对象,避免构造函数参数爆炸。
Spring/Boot 常见场景:
SpringApplicationBuilder(启动参数/环境组合)- 各类
*Builder:如UriComponentsBuilder、WebClient.Builder(在 Spring WebFlux 中)
策略模式(Strategy)
核心:把“可替换的算法/规则”抽象成接口,运行时选择不同实现。
Spring 里的体现:
- 典型扩展点:
Converter、HandlerMethodArgumentResolver、HttpMessageConverter、PasswordEncoder、CacheManager等 - 业务里也非常常用:按支付渠道/活动规则/风控策略选择不同实现,替代大段
if-else
一个最小可用的业务例子(按渠道处理回调):
1 | public interface PayCallbackHandler { |
代理模式(Proxy)
核心:为目标对象提供一个“替身”,在不改目标代码的情况下增强能力(日志、事务、鉴权、缓存等)。
Spring 里最典型的体现:
- AOP:
@Transactional、@Async、@Cacheable、@Validated等,大多数都是通过代理增强实现 - 代理常见两类:JDK 动态代理(基于接口)和 CGLIB(基于子类)
实战注意:同类内部方法自调用(self-invocation)可能绕过代理,导致事务/缓存不生效。
观察者模式(Observer / 发布-订阅)
核心:事件发布者与订阅者解耦,发布者只“发事件”,订阅者各自处理。
Spring 里的体现:
ApplicationEventPublisher+@EventListener- 适合做:异步通知、审计日志、站内消息、缓存刷新等(需要与主流程解耦的动作)
1 | public record OrderPaidEvent(Long orderId) {} |
责任链模式(Chain of Responsibility)
核心:把一系列处理步骤串成链,每个节点只关注自己的一段逻辑,且可以选择“放行/拦截”。
Spring 里的体现:
- Servlet Filter 链(
Filter) - Spring MVC 拦截器链(
HandlerInterceptor) - Spring Security Filter Chain(非常典型的责任链)
业务里常见:参数校验 → 幂等校验 → 风控 → 业务处理 → 审计/通知。
适配器模式(Adapter)
核心:把一个接口“转换成”另一个接口,让不兼容的组件能协同工作。
Spring 里的体现:
- Spring MVC 的
HandlerAdapter:统一适配不同类型的 Controller(让 DispatcherServlet 只面向统一调用入口) - 各类
*Adapter/*Configurer:对外暴露更友好的扩展接口,同时内部保持稳定实现
装饰器模式(Decorator)
核心:在不改变原对象类型/调用方式的前提下,动态叠加增强能力。
Spring 里的常见体现:
- Servlet API 的
HttpServletRequestWrapper/HttpServletResponseWrapper(对请求/响应做包装增强) - 各类“包装型”实现:在保留原始对象能力的同时叠加监控、埋点、限流等
门面模式(Facade)
核心:为复杂子系统提供一个简单统一的入口。
Spring 里的体现:
JdbcTemplate:对 JDBC 的繁琐流程做门面封装(连接、异常转换、资源释放等)RestTemplate(或WebClient):对 HTTP 调用提供更统一的高层 API
模板方法模式(Template Method)在 Spring 里的延伸
你上面已经详细介绍了模板方法模式;在 Spring 生态里常见“模板类”还有:
JdbcTemplate:固定流程 + 回调扩展(RowMapper/PreparedStatementSetter等)RedisTemplate:固定序列化/执行流程 + 提供扩展点TransactionTemplate:固定事务边界流程 + 回调执行业务
这类模板类的价值是:把资源管理、异常转换、边界控制等“重复且容易错”的部分收敛到框架层。
