当前位置: 首页 > news >正文

从豆浆机到MyBatis:模板方法模式在主流Java框架里的“隐形”应用

从豆浆机到MyBatis:模板方法模式在主流Java框架里的“隐形”应用

当你清晨用豆浆机制作不同口味的饮品时,是否想过这和Java框架的设计思想竟有异曲同工之妙?选豆、浸泡、研磨这些固定流程就像代码中的算法骨架,而添加红豆或花生则如同子类对特定步骤的个性化实现。这种"固定流程+可变细节"的智慧,正是模板方法模式(Template Method Pattern)的精髓所在。

在Java生态中,许多看似复杂的框架实现,其实都藏着这种设计模式的巧妙应用。本文将带你在MyBatis、Spring等主流框架的源码中进行一次"寻宝之旅",揭示大师们如何用模板方法模式构建既稳定又灵活的架构。无论你是想深入理解框架原理,还是希望提升自己的代码设计能力,这些隐藏在常见API背后的模式应用都值得细细品味。

1. 模板方法模式的核心哲学

模板方法模式本质上是一种"好莱坞原则"(Don't call us, we'll call you)的体现——父类控制整体流程,子类只需关注自己需要改变的部分。这种反向控制的结构让代码既保持了统一性,又具备了扩展性。

1.1 模式结构解析

典型的模板方法模式包含以下关键组件:

public abstract class AbstractTemplate { // 模板方法,定义算法骨架 public final void templateMethod() { step1(); step2(); step3(); } // 固定实现步骤 private void step1() { System.out.println("执行固定步骤1"); } // 抽象方法,由子类实现 protected abstract void step2(); // 钩子方法,可选覆盖 protected void step3() { System.out.println("默认步骤3实现"); } }

这种结构带来了三个显著优势:

  1. 代码复用:将不变部分集中到父类,避免重复代码
  2. 扩展可控:子类只能修改允许变化的部分,不会破坏整体结构
  3. 逻辑清晰:算法流程一目了然,维护者能快速理解整体逻辑

1.2 现实世界的类比

理解设计模式最好的方式就是从生活场景寻找对应关系:

生活场景对应代码概念
咖啡制作流程算法骨架
选择咖啡豆品种子类具体实现
自定义糖量钩子方法
咖啡机操作手册模板方法中的固定步骤

这种将现实世界抽象为代码模式的能力,正是区分普通开发者和架构师的重要标志。

2. MyBatis中的执行器体系

MyBatis作为ORM框架的核心价值之一,就是将对数据库的操作抽象为统一的执行流程。深入其Executor接口的实现,你会发现这正是模板方法模式的经典应用场景。

2.1 BaseExecutor的模板设计

BaseExecutor作为所有执行器的基类,定义了数据库操作的标准流程:

public abstract class BaseExecutor implements Executor { // 查询模板方法 public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) { // 1. 获取绑定SQL BoundSql boundSql = ms.getBoundSql(parameter); // 2. 创建缓存Key CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); // 3. 执行查询(抽象方法) return queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } // 由子类实现的抽象方法 protected abstract <E> List<E> queryFromDatabase(...); }

这种设计确保了:

  • 所有执行器都遵循相同的缓存处理逻辑
  • 子类只需关注具体的数据库交互实现
  • 新增执行器类型时不会破坏现有流程

2.2 不同执行器的实现对比

MyBatis提供了多种执行器实现,它们在模板方法的基础上各自扩展:

执行器类型扩展点实现应用场景
SimpleExecutor每次执行都创建新Statement默认配置
ReuseExecutor复用预处理Statement高频相同SQL场景
BatchExecutor批量操作优化大批量数据写入

源码阅读技巧:在IDE中查看BaseExecutor类,注意哪些方法是final的(不可修改流程),哪些是abstract的(必须实现),哪些是普通方法(可选覆盖)。

3. Spring框架中的模板应用

Spring框架堪称设计模式的百科全书,其中模板方法模式的应用更是随处可见。让我们聚焦两个典型案例:JdbcTemplate和事务管理。

3.1 JdbcTemplate的callback机制

JdbcTemplate通过回调接口将可变部分抽象出来,保持核心流程不变:

public class JdbcTemplate { public <T> T query(String sql, ResultSetExtractor<T> rse) { // 1. 获取连接 Connection con = DataSourceUtils.getConnection(getDataSource()); try { // 2. 准备语句 Statement stmt = con.createStatement(); try { // 3. 执行查询 ResultSet rs = stmt.executeQuery(sql); try { // 4. 处理结果(回调扩展点) return rse.extractData(rs); } finally { rs.close(); } } finally { stmt.close(); } } finally { DataSourceUtils.releaseConnection(con, getDataSource()); } } }

这种设计带来了极佳的灵活性:

  • 开发者可以自定义ResultSetExtractor实现特殊结果处理
  • Spring内置了RowMapper等常用回调接口
  • 资源管理(连接、语句、结果集)由模板统一处理

3.2 事务管理的模板流程

Spring事务抽象的核心类PlatformTransactionManager也采用了模板方法:

public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager { public final TransactionStatus getTransaction(...) { // 1. 获取事务 Object transaction = doGetTransaction(); // 2. 检查是否存在事务 if (isExistingTransaction(transaction)) { // 处理已存在事务 return handleExistingTransaction(...); } // 3. 检查超时设置 if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) { throw new InvalidTimeoutException(...); } // 4. 处理新事务(抽象方法) return startTransaction(definition, transaction, debugEnabled, suspendedResources); } protected abstract Object doGetTransaction(); protected abstract void doBegin(...); protected abstract void doCommit(...); }

这种架构使得:

  • 事务获取和提交的标准流程得以统一
  • 不同数据源只需实现特定的几个方法
  • 新增事务管理器时不会引入流程不一致的风险

4. Servlet API的设计智慧

即使是最基础的Java Web开发,也离不开模板方法模式的应用。HttpServlet类就是最直观的例子。

4.1 HttpServlet的服务流程

HttpServlet通过模板方法将HTTP请求分发给对应的处理方法:

public abstract class HttpServlet extends GenericServlet { protected void service(HttpServletRequest req, HttpServletResponse resp) { String method = req.getMethod(); if (method.equals("GET")) { doGet(req, resp); } else if (method.equals("POST")) { doPost(req, resp); } // ...其他方法处理 } protected void doGet(HttpServletRequest req, HttpServletResponse resp) { // 默认实现返回405错误 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); } protected void doPost(HttpServletRequest req, HttpServletResponse resp) { // 同上 } }

这种设计实现了:

  • 统一的HTTP方法分发逻辑
  • 子类只需覆盖关心的请求方法
  • 默认提供合理的错误处理

4.2 框架中的过滤器链

Servlet规范中的FilterChain同样体现了模板方法思想:

public interface FilterChain { void doFilter(ServletRequest request, ServletResponse response); } public class ApplicationFilterChain implements FilterChain { private int pos = 0; private int n = 0; private Filter[] filters; public void doFilter(ServletRequest request, ServletResponse response) { if (pos < n) { Filter filter = filters[pos++]; filter.doFilter(request, response, this); } else { // 执行实际servlet servlet.service(request, response); } } }

每个过滤器只需关注自己的处理逻辑,而过滤器之间的调用顺序由FilterChain模板控制,这种设计让过滤器组合变得非常灵活。

5. 日常开发中的模式实践

理解了框架中的设计模式后,我们应该思考如何将这种思维应用到日常开发中。以下是三个典型的应用场景。

5.1 报表生成流程抽象

假设我们需要实现多种格式的报表导出功能:

public abstract class ReportGenerator { public final void generateReport(ReportData data, OutputStream out) { validateData(data); ReportTemplate template = prepareTemplate(data); renderReport(template, out); afterGenerate(data); } protected void validateData(ReportData data) { // 基础校验逻辑 } protected abstract ReportTemplate prepareTemplate(ReportData data); protected abstract void renderReport(ReportTemplate template, OutputStream out); protected void afterGenerate(ReportData data) { // 默认空实现 } }

这样新增报表类型时,只需继承并实现关键步骤:

public class PdfReportGenerator extends ReportGenerator { protected ReportTemplate prepareTemplate(ReportData data) { // PDF模板准备逻辑 } protected void renderReport(ReportTemplate template, OutputStream out) { // 使用iText等库渲染PDF } }

5.2 支付网关集成

支付接口通常有相似的流程:参数校验→加密→请求→结果处理:

public abstract class PaymentGateway { public final PaymentResult pay(PaymentRequest request) { validate(request); String encrypted = encrypt(request); String response = sendRequest(encrypted); return processResponse(response); } protected abstract String encrypt(PaymentRequest request); protected abstract String sendRequest(String encryptedData); protected abstract PaymentResult processResponse(String response); private void validate(PaymentRequest request) { // 通用校验逻辑 } }

5.3 业务规则引擎

对于需要灵活扩展的业务规则处理:

public abstract class BusinessRuleEngine { public final RuleExecutionResult execute(RuleContext context) { preProcess(context); RuleExecutionResult result = applyRules(context); postProcess(result); return result; } protected void preProcess(RuleContext context) { // 上下文预处理 } protected abstract RuleExecutionResult applyRules(RuleContext context); protected void postProcess(RuleExecutionResult result) { // 默认空实现 } }

6. 模式应用的注意事项

虽然模板方法模式非常实用,但在实际应用中也需要考虑以下几点:

6.1 何时使用模板方法

适合采用模板方法模式的场景通常具有以下特征:

  • 存在多个相似流程,主要步骤相同但某些细节不同
  • 需要严格控制流程执行顺序
  • 希望避免重复代码同时保持扩展性
  • 子类只需要改变算法的部分内容而非全部

6.2 潜在的设计陷阱

过度使用模板方法可能导致:

  • 类层次过深,增加系统复杂度
  • 父类变得过于庞大,承担过多责任
  • 子类被迫实现不需要的方法(可用钩子方法缓解)

6.3 与其他模式的关系

模板方法模式常与其他模式配合使用:

  • 工厂方法模式:模板方法中的某些步骤可能使用工厂方法创建对象
  • 策略模式:可以用策略模式替换模板方法中的某些步骤
  • 观察者模式:模板方法中的某些步骤可能触发观察者通知

在MyBatis的Executor实现中,实际上就结合了模板方法和装饰器模式(通过CachingExecutor装饰基础执行器)。

http://www.jsqmd.com/news/713995/

相关文章:

  • OpenClaw AgenticHub 架构解析:智能体系统如何真正具备执行能力
  • 手把手教你用TJA1145收发器搭建CANFD网络(附MCU电平转换避坑指南)
  • Qwen3.5-9B-GGUF快速上手:支持中文的9B开源模型本地部署零基础指南
  • 别再只查表了!手把手教你用USB-CAN适配器的高级模式自定义波特率
  • 别再傻傻分不清了!OpenCV透视变换:cv2.findHomography() 和 cv2.getPerspectiveTransform() 到底怎么选?
  • 一篇搞定2026年简历模板服务商选购,避坑+选品全说清
  • 【项目实战】从 0 到 1 构建智能协同云图库(二):项目后端初始化
  • Android Kotlin OkHttp3 WebSocket 长连接与 Gson 数据解析系统笔记
  • Boss-Key老板键:3分钟掌握Windows窗口隐身术,告别工作尴尬时刻
  • Python的抽象基类abc模块与isinstance类型检查的注册机制
  • 【信创攻坚必备】:Python 3.11适配达梦V8、OceanBase 4.3、TiDB 7.5的3类驱动兼容性验证报告(附官方未公开API补丁)
  • Triton Server模型热更新避坑实战:从EXPLICIT模式到内存管理(含tcmalloc配置)
  • Sentrifugo完整指南:免费开源HR系统的快速上手教程
  • 5步解锁加密音乐:Unlock-Music完全使用指南
  • 20252426汪裕植 2025-2026-2《Python程序设计》实验3报告
  • 微信聊天记录永久保存终极指南:如何安全备份并智能分析你的数字记忆
  • Windows窗口置顶神器:5分钟学会让任意应用永远显示在最上层
  • Halcon仿射变换的“黑话”解读:vector_angle_to_rigid和hom_mat2d_rotate到底谁绕谁转?
  • Blazor终极使用指南:用C构建现代Web应用的完整教程
  • 保姆级教程:用Wireshark抓包,5分钟看懂TCP三次握手和四次挥手(附实战截图)
  • TVA在集成电路芯片设计中的应用:以华为海思、紫光展锐为例(六)
  • OpenCode快速部署指南:3步搭建你的AI编程助手,支持远程操作
  • 黄金麻规格板选购注意啥,鑫邦石业产品口碑好吗 - 工业品牌热点
  • NewTab Redirect! 终极指南:5步打造你的专属Chrome新标签页
  • 实测!YOLOv5灰度图训练完整避坑指南:从源码修改到性能对比(附6个报错解决方案)
  • Typora高级设置文件conf.user.json全解析:从快捷键到字体,打造你的专属写作环境
  • SCMP各模块重点解析:逐个突破6大科目 - 众智商学院官方
  • 互联网架构师联合总结的 Java 面试攻略
  • 3分钟搞定B站缓存视频合并:安卓神器让离线观看更轻松
  • 5步掌握Boss-Key老板键:一键隐藏窗口的终极隐私保护指南