Java 23 种设计模式:从踩坑到精通 | 番外:组合 vs 解释器 —— 结构树 vs 计算树
Java 23 种设计模式:从踩坑到精通 | 番外:组合 vs 解释器 —— 结构树 vs 计算树
摘要:组合模式和解释器模式都用到了树形结构,但组合模式的树是“结构树”——叶子与容器行为统一,客户端一致处理;解释器模式的树是“计算树”——每种节点有独立的求值逻辑,通过递归计算得出结果。本文从文件系统管理器和四则运算计算器两个场景出发,结合代码对比、UML 分析和 JDK
Pattern、Spring SpEL 源码,帮你彻底分清这对“树形结构型”模式。
🗺️本文阅读地图(3 分钟速览)
- 为什么文件系统是组合模式,表达式求值是解释器模式?
- UML 对比:统一操作 vs 递归求值
- 手写文件系统管理器 vs 四则运算计算器,看代码感受差异
- 组合模式中的
operation()和解释器中的interpret()本质区别- 面试必问:“组合和解释器都用了树,到底有什么区别?”
📖《Java 23 种设计模式:从踩坑到精通》
开篇:系列介绍与目录 |当前:番外 · 组合 vs 解释器
🔗 返回系列总目录
文章目录
- Java 23 种设计模式:从踩坑到精通 | 番外:组合 vs 解释器 —— 结构树 vs 计算树
- 1. 从“文件系统”和“四则运算”两个场景说起
- 1.1 场景一:文件系统管理器(组合模式)
- 1.2 场景二:四则运算计算器(解释器模式)
- 1.3 关键差异已浮现
- 2. UML 对比
- 3. 三大核心区别
- 4. JDK 源码深度对比
- 4.1 AWT 组件树(组合模式)
- 4.2 Java 正则表达式(解释器模式)
- 5. 组合模式可以作为解释器模式的“基础结构”
- 6. 面试必问 + 追问连环炮
- 🧭 《Java 23 种设计模式:从踩坑到精通》快速导航
1. 从“文件系统”和“四则运算”两个场景说起
1.1 场景一:文件系统管理器(组合模式)
假设你在开发一个文件管理系统,需要展示文件夹和文件的层级结构。文件夹里可以有文件,也可以有子文件夹。你需要递归展示整个目录树,但不管是文件还是文件夹,对客户端来说最好能统一操作。
// 组合模式:统一处理叶子(文件)和容器(文件夹)FileSystemNoderoot=newFolderNode("root");FileSystemNodedocs=newFolderNode("docs");FileSystemNodefile1=newFileNode("readme.txt");FileSystemNodefile2=newFileNode("image.png");root.add(docs);docs.add(file1);docs.add(file2);// 客户端不用区分文件和文件夹,统一调用 show()root.show(0);// 输出:// 文件夹:root// 文件夹:docs// 文件:readme.txt// 文件:image.png💬白话:客户端只调用
show(),不管是文件还是文件夹都照常执行。组合模式的核心是统一叶子与容器的接口,让客户端一致处理。
1.2 场景二:四则运算计算器(解释器模式)
现在你要实现一个表达式计算器,能够解析并计算a + b - c这样的表达式。变量a、b、c是叶子节点,+、-是运算符节点。你需要根据语法规则递归求值。
// 解释器模式:构建语法树,递归求值Contextctx=newContext();ctx.setVariable("a",10);ctx.setVariable("b",5);ctx.setVariable("c",2);// 构建语法树:a + b - cExpressionexpression=newSubtract(newAdd(newVariable("a"),newVariable("b")),newVariable("c"));intresult=expression.interpret(ctx);System.out.println("a + b - c = "+result);// 13💬白话:
Add节点和Subtract节点各自有自己的求值逻辑,Variable节点直接取值。每种节点的interpret()行为完全不同。解释器模式的核心是每种节点有独立的计算逻辑,通过递归得出最终结果。
1.3 关键差异已浮现
- 组合模式:文件和文件夹的
show()行为相似——都是展示自己,文件夹多了遍历子节点; - 解释器模式:
Add.interpret()做加法,Subtract.interpret()做减法,Variable.interpret()取值——行为完全不同。
2. UML 对比
3. 三大核心区别
| 对比维度 | 组合模式 | 解释器模式 |
|---|---|---|
| 树的性质 | 结构树——表示部分-整体层次关系 | 计算树——表示语法规则和求值逻辑 |
| 节点行为 | operation()统一——叶子与容器行为相似 | interpret()各不相同——每种节点求值逻辑不同 |
| 是否管理子节点 | ✅ 容器有add()/remove() | ❌ 节点不暴露管理方法 |
| 客户端操作 | 调用顶层节点的方法,递归遍历整棵树 | 调用顶层节点的interpret(),递归计算出结果 |
| 典型应用 | 文件系统、组织架构、AWT 组件树 | 四则运算、正则表达式、Spring SpEL |
4. JDK 源码深度对比
4.1 AWT 组件树(组合模式)
// AWT 中,Panel 是容器,Button 是叶子,都继承自 Component// add() 方法在容器中管理子组件,paint() 递归渲染整棵组件树Panelpanel=newPanel();Buttonbtn=newButton("点击");panel.add(btn);// 容器管理子组件panel.paint(graphics);// 递归渲染所有子组件为什么是组合模式?
Button和Panel都继承自Component,接口统一;Panel通过add()管理子组件,Button没有子组件;- 调用
paint()时,Panel递归调用所有子组件的paint()——行为一致。
4.2 Java 正则表达式(解释器模式)
// Pattern 内部将正则表达式编译为一棵语法树Patternpattern=Pattern.compile("a(b|c)*d");Matchermatcher=pattern.matcher("abcd");booleanmatches=matcher.matches();为什么是解释器模式?
- 正则表达式
a(b|c)*d被解析为一棵语法树; a、b、c、d是终结符(字符字面量),|和*是非终结符(运算符);- 匹配时递归遍历语法树,每种节点(字符、选择、重复)执行不同的匹配逻辑——行为各不相同。
5. 组合模式可以作为解释器模式的“基础结构”
解释器模式通常建立在组合模式之上——语法树本身就是一种树形结构,非终结符节点包含子表达式,这与组合模式的容器-叶子结构高度相似。
| 对比维度 | 组合模式 | 解释器模式 |
|---|---|---|
| 关注点 | 结构的组织方式 | 结构的计算逻辑 |
| 组合关系 | 独立使用 | 通常建立在组合模式之上 |
| 面试常见问法 | “如何统一处理树形结构?” | “如何设计一个表达式解析器?” |
💡一句话总结:组合模式负责“搭架子”(树形结构),解释器模式负责“填逻辑”(每种节点的计算规则)。Spring SpEL 就是先构建组合树,再递归求值的典型代表。
6. 面试必问 + 追问连环炮
基础必问
- 组合模式和解释器模式都用到了树,有什么区别?
👉 组合关注“结构统一”——叶子与容器行为一致,客户端统一操作;解释器关注“递归求值”——每种节点有不同的计算逻辑。 - 什么时候用组合?什么时候用解释器?
👉 需要统一处理树形结构(文件系统、菜单)→ 组合;需要定义语法规则并求值(表达式、规则引擎)→ 解释器。
面试官追问
- “解释器模式和组合模式能配合使用吗?”
👉 可以。解释器模式的语法树通常建立在组合模式之上——用组合模式管理树结构,用解释器模式实现每个节点的求值逻辑。Spring SpEL 就是这样做的。 - “为什么复杂语法不推荐解释器模式?”
👉 因为每个语法规则都要对应一个类,类数量会爆炸(类膨胀问题);递归求值性能远低于直接编译。此时应用 ANTLR、JavaCC 等专业解析器生成工具。 - “组合模式中,如果只想遍历叶子节点怎么办?”
👉 在 Component 接口中定义isLeaf()方法,或使用访问者模式对不同节点类型分别处理。
🎉恭喜:如果你能立刻画出文件系统的树形结构和四则运算的语法树,并说出“组合关注结构统一,解释器关注递归求值”,你已经掌握了这两棵树最核心的区别。
💡延伸阅读:本文是组合模式与解释器模式的深度对比。如果你想先了解每种模式的完整原理、UML、代码实现和面试题,可以先阅读正篇——组合模式:树形结构处理,部分与整体一视同仁 和 解释器模式:自己动手写一个小语言解释器,再回来看这篇对比,效果更佳。
🧭 《Java 23 种设计模式:从踩坑到精通》快速导航
- 开篇:系列介绍与目录
- 当前:番外 · 组合 vs 解释器 —— 结构树 vs 计算树(你在这里)
- 📖 延伸阅读:组合模式正篇 | 解释器模式正篇
- 创建型模式汇总
- 结构型模式汇总
- 行为型模式汇总
🔔 关注《Java 23 种设计模式:从踩坑到精通》,用 25 篇文章彻底吃透设计模式。
📦福利预告:全系列代码及 UML 源码将在完结时统一打包开放,点击「关注」「收藏」第一时间获取。
📌 除了设计模式,我也在深挖智能物流实战(WMS、托盘调度、机器学习落地)。欢迎点击头像,看看专栏 《出版社物流WMS智能调度实战》。技术相通,思路可鉴。