Java 23 种设计模式:从踩坑到精通 | 番外:策略 vs 模板方法 —— 组合与继承的终极对决
Java 23 种设计模式:从踩坑到精通 | 番外:策略 vs 模板方法 —— 组合与继承的终极对决
摘要:策略模式和模板方法模式都能消除重复代码,但策略用“组合”替换整体算法,模板方法用“继承”固定算法骨架。它们的核心区别在于控制权的归属——策略模式由客户端选择算法,模板方法由父类控制流程。本文从电商促销和数据同步两个实战场景出发,结合代码对比、UML 分析和 JDK 源码,带你彻底理解“组合优于继承”的真正含义。
🗺️本文阅读地图(3 分钟速览)
- 为什么策略和模板方法都能消除重复?它们到底像在哪里?
- UML 对比:接口+组合 vs 抽象类+继承
- 手写促销策略引擎 vs 数据同步模板,感受差异
- DK
Comparator(策略) vsHttpServlet(模板方法)源码对比- 面试必问:“什么时候用策略?什么时候用模板方法?”
📖《Java 23 种设计模式:从踩坑到精通》
开篇:系列介绍与目录 |当前:番外 · 策略 vs 模板方法
🔗 返回系列总目录
文章目录
- Java 23 种设计模式:从踩坑到精通 | 番外:策略 vs 模板方法 —— 组合与继承的终极对决
- 1. 从“电商促销”和“数据同步”两个场景说起
- 1.1 场景一:电商促销(策略模式)
- 1.2 场景二:数据同步(模板方法模式)
- 2. UML 对比:接口+组合 vs 抽象类+继承
- 2.1 策略模式 UML(组合)
- 2.2 模板方法模式 UML(继承)
- 3. 四大核心区别
- 4. JDK 源码对比
- 4.1 `Comparator`(策略模式)
- 4.2 `HttpServlet`(模板方法模式)
- 5. 面试必问 + 追问连环炮
- 🧭 《Java 23 种设计模式:从踩坑到精通》快速导航
1. 从“电商促销”和“数据同步”两个场景说起
1.1 场景一:电商促销(策略模式)
电商系统有多种促销算法——满减、打折、立减。不同活动、不同用户可能使用不同的促销策略。这些算法整体可替换,你需要在运行时灵活选择用哪种促销。
// 策略模式:客户端选择算法Orderorder=newOrder(500);order.setPromotionStrategy(newFullReductionStrategy());// 满减doubleprice1=order.checkout();order.setPromotionStrategy(newDiscountStrategy());// 切换打折doubleprice2=order.checkout();💬特征:算法之间完全独立,客户端显式选择使用哪个策略。
1.2 场景二:数据同步(模板方法模式)
不同数据源的同步流程大体相同——连接、抽取、转换、加载、断开。这些步骤的流程固定,但“抽取什么数据”、“怎么转换”各不相同。
// 模板方法模式:父类固定流程,子类填空publicabstractclassDataSyncTemplate{publicfinalvoidsync(){// 模板方法:final,防止篡改connect();extractData();// 子类实现transformData();// 钩子:可选覆盖loadData();// 子类实现disconnect();}// ...}💬特征:流程骨架固定,子类只能填空,不能改变顺序。
2. UML 对比:接口+组合 vs 抽象类+继承
2.1 策略模式 UML(组合)
2.2 模板方法模式 UML(继承)
UML 的关键差异:
- 策略模式使用接口 + 组合,
Context持有Strategy引用,由客户端注入; - 模板方法模式使用抽象类 + 继承,父类定义骨架,子类通过继承实现可变步骤;
- 策略的
Context提供setStrategy()方法,模板方法的父类不提供切换方法——因为骨架是固定的。
3. 四大核心区别
| 对比维度 | 策略模式 | 模板方法模式 |
|---|---|---|
| 核心机制 | 接口 + 组合 | 抽象类 + 继承 |
| 控制权 | 客户端选择算法 | 父类控制流程,子类只填空 |
| 替换粒度 | 整个算法可替换 | 算法骨架固定,部分步骤可变 |
| 复用方式 | 复用策略类(组合) | 复用父类通用代码(继承) |
| 典型应用 | Comparator、支付方式 | HttpServlet、JdbcTemplate |
💡简单记忆:策略是“组合替换”——整个算法随便换;模板方法是“继承填空”——骨架固定,填细节。
4. JDK 源码对比
4.1Comparator(策略模式)
// Comparator 是策略接口,每种排序规则是一个具体策略List<String>list=Arrays.asList("apple","banana","cherry");list.sort(Comparator.naturalOrder());// 正序策略list.sort(Comparator.reverseOrder());// 倒序策略list.sort(Comparator.comparing(String::length));// 按长度策略💬 客户端显式选择排序策略,策略之间完全独立。
4.2HttpServlet(模板方法模式)
// HttpServlet 是模板父类,service() 是模板方法publicclassMyServletextendsHttpServlet{@OverrideprotectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp){// 只填空:处理 GET 请求}@OverrideprotectedvoiddoPost(HttpServletRequestreq,HttpServletResponseresp){// 只填空:处理 POST 请求}}💬
service()方法是final的,流程固定——子类不能改变“先判断方法类型再分发”的骨架。
5. 面试必问 + 追问连环炮
基础必问
- 策略模式和模板方法模式的区别?
👉 策略用组合替换整体算法(客户端选择),模板方法用继承固定骨架(父类控制流程)。 - 什么时候用策略?什么时候用模板方法?
👉 算法整体可替换、需要灵活组合 → 策略;流程固定、只有部分步骤不同 → 模板方法。
面试官追问
- “为什么说策略模式体现了‘组合优于继承’?”
👉 策略通过接口+组合来替换算法,可以在运行时动态切换;继承只能在编译时确定,且子类受限于父类的骨架设计。组合比继承更灵活。 - “模板方法模式中钩子方法的作用?”
👉 钩子方法提供默认实现,子类可选覆盖。它让父类在固定流程中留出“可开关的分支”——例如wantCondiments()控制是否加调料,子类重写它就能改变流程行为。 - “
JdbcTemplate是策略还是模板方法?”
👉 模板方法模式。JdbcTemplate固定了“获取连接→执行SQL→处理结果集→释放资源”的流程,用户只通过回调接口填写 SQL 和结果映射逻辑。 - “策略模式和模板方法能配合使用吗?”
👉 可以。模板方法固定流程,策略在流程中的某个步骤提供多种算法选择。例如数据同步框架中,extractData()步骤可以用策略模式支持多种数据源(MySQL、PostgreSQL、MongoDB)。
🎉恭喜:如果你能立刻说出
Comparator是策略模式(组合替换),HttpServlet是模板方法模式(继承填空),你已经掌握了行为型模式中最核心的“组合 vs 继承”设计哲学。
💡延伸阅读:本文是策略模式与模板方法模式的深度对比。如果你想先了解每种模式的完整原理、UML、代码实现和面试题,可以先阅读正篇——策略模式:算法族的封装与切换,告别 if-else 和 模板方法模式:定义算法骨架,交给子类填充细节,再回来看这篇对比,效果更佳。
🧭 《Java 23 种设计模式:从踩坑到精通》快速导航
- 开篇:系列介绍与目录
- 当前:番外 · 策略 vs 模板方法 —— 组合与继承的终极对决(你在这里)
- 📖 延伸阅读:策略模式正篇 | 模板方法模式正篇
- 创建型模式汇总
- 结构型模式汇总
- 行为型模式汇总
🔔 关注《Java 23 种设计模式:从踩坑到精通》,用 25 篇文章彻底吃透设计模式。
📦福利预告:全系列代码及 UML 源码将在完结时统一打包开放,点击「关注」「收藏」第一时间获取。
📌 除了设计模式,我也在深挖智能物流实战(WMS、托盘调度、机器学习落地)。欢迎点击头像,看看专栏 《出版社物流WMS智能调度实战》。技术相通,思路可鉴。