解释器模式是将结构化输入(如数学式、规则)转为可执行对象的实用方法,核心是用类表语法单位、组合建逻辑、递归完成解释,含终结符、非终结符和上下文三类角色。

解释器模式不是用来“写编程语言”的炫技工具,而是把一段有结构的输入(比如数学式、条件语句、优惠规则)变成可执行对象的实用方法。它的核心是:用类代表语法单位,用组合构建逻辑关系,靠递归完成解释。
理解三个关键角色:谁在干活?
不用背定义,记住这三类对象的实际分工:
-
终结符表达式:处理最基础的“原子单元”,比如数字
5、变量名"price"、字符串"discount"。它不依赖别的表达式,自己就能给出结果。 -
非终结符表达式:处理“组合逻辑”,比如
Plus、IfThen、AndRule。它内部持有其他表达式(可以是终结符,也可以是别的非终结符),解释时会递归调用它们。 - 上下文(Context):不是“环境配置”,而是运行时的共享数据池。变量值、全局开关、用户信息、临时缓存都往里放——所有表达式都能读写它,避免参数层层传递。
动手写一个最小可用的计算器
目标:解析并计算形如 "x + 3 * 2" 的表达式(忽略运算符优先级,按从左到右顺序)。
- 先定义统一接口:
Expression.interpret(Context),返回整数结果; - 写两个终结符:
VariableExpression("x")从 Context 取值,ConstantExpression(3)直接返回数字; - 写一个非终结符:
MultiplyExpression(left, right),解释时调用左右子表达式的interpret()再相乘; - 客户端手动组装树:
new AddExpression(new VariableExpression("x"), new MultiplyExpression(new ConstantExpression(3), new ConstantExpression(2))); - 准备 Context 并传入:
context.setVariable("x", 10),再调用根节点的interpret(context)得到结果。
什么时候该用,什么时候绕开?
适合场景有明确边界,别硬套:
- ✅ 规则简单、变化频繁:比如电商的满减规则引擎(“满300减50”“会员折上95折”),新增一条规则只需加一个表达式类;
- ✅ 输入格式固定、结构清晰:如 IoT 设备指令
"if temp > 25 then ac on",天然对应 if-then 结构; - ❌ 表达式极长或嵌套极深:递归解释可能栈溢出,且调试困难;
- ❌ 需要高性能或复杂语法:比如带括号优先级、函数调用、错误精确定位——该上 ANTLR 或手写递归下降解析器了。
常见踩坑点提醒
实际落地时,这几个细节容易被忽略:
- 上下文不是只读的:前一个表达式可以往 Context 存中间结果(如匹配次数、当前状态),后一个表达式接着用——这是实现状态流转的关键;
- 抽象语法树(AST)由客户端构建,不是自动解析出来的:你得自己写词法切分+语法组装逻辑,或者额外配一个 parser;
- 不要试图用解释器模式替代 if-else 或策略模式:如果只有两三种判断分支,硬套解释器反而增加理解成本;
- 终结符和非终结符的界限可以模糊:比如一个
DateRangeExpression看似复杂,但若它不组合其他表达式,就仍是终结符。

















