← 返回题目列表

解释器模式有哪些角色?执行流程是怎样的?

高频 中等 第 5 / 25 题 更新于 2026/07/28
解释器模式角色表达式树执行流程

简化版

解释器模式包括抽象表达式、终结符表达式、非终结符表达式、上下文和客户端。流程是客户端根据语法构建表达式树,然后调用根表达式的解释方法,表达式节点递归解释子节点并结合上下文得到结果。

详细版

角色说明:

  • AbstractExpression:定义 interpret(context)
  • TerminalExpression:处理最小语法单元,如变量、数字、布尔值。
  • NonterminalExpression:处理组合规则,如加法、与、或、比较。
  • Context:保存变量值、环境信息和解释过程状态。
  • Client:负责构建表达式树并调用解释。

执行流程:

  1. 输入表达式或规则。
  2. 解析成表达式对象树。
  3. 创建 Context。
  4. 调用根节点 interpret(context)
  5. 节点递归解释子表达式。
  6. 返回最终结果。

解释器模式通常把“解析”和“解释”分开,解析负责建树,解释负责执行语义。

完整版教学

一、抽象表达式

抽象表达式定义统一接口:

interface Expression {
    boolean interpret(Context context);
}

所有具体表达式都实现这个接口。这样客户端只需要面向 Expression 编程。

二、终结符和非终结符

终结符表达式是不能继续拆分的单元。例如变量表达式、数字表达式、常量表达式。

非终结符表达式由其他表达式组合而成。例如 AndExpression 包含左右两个表达式,解释结果是左右表达式都为 true。

这种结构天然适合递归。

三、Client 为什么也重要

很多讲解会忽略 Client,但实际项目里构建表达式树很关键。字符串规则要先经过词法分析、语法分析,才能变成表达式树。

如果规则来源是配置或用户输入,解析阶段还要做错误提示和安全校验。

四、常见误区与工程判断

不要把解析字符串和解释执行混在一个巨大方法里。这样一开始简单,后面加规则会越来越乱。

工程中可以先把表达式对象模型设计清楚,再决定解析方式。简单场景可以手写解析,复杂场景用 ANTLR、表达式引擎或规则引擎。

五、从输入到结果要分三层理解

解释器模式的完整流程可以拆成三层:第一层是语法建模,把每种语法规则抽象成 Expression;第二层是表达式树构建,把输入规则解析成对象结构;第三层是解释执行,从根表达式开始递归调用 interpret(context) 得到结果。

很多面试答案只讲 Expression 和 Context,却忽略“表达式树从哪里来”。如果规则直接写在代码里,客户端可以手动 new 出表达式树;如果规则来自配置文件或用户输入,就必须有解析阶段。解释器模式本身不等于解析器,它主要描述解析后的表达式对象如何执行。

回答时可以把角色串起来:TerminalExpression 处理最小语法单元,NonTerminalExpression 组合子表达式,Context 提供解释所需的外部变量,Client 或 Parser 负责构建表达式树。这样就能把静态类图讲成动态流程。

六、用工程约束检验答案

完整流程至少有 3 段:词法器把 age >= 18 转成 token,解析器构造比较表达式,Expression 再从 Context 读取 age 求值。若 age=20,结果为 true;Context 并不负责识别 >= 的语法。

检查项核心判断工程含义
Client/Parser把输入构造成表达式树处理语法结构
Expression实现解释契约递归计算语义
Context提供 age=20 等运行数据与 AST 分离

把关键关系压缩成一条可复述的路径:

"age >= 18"
 -> [IDENT, GE, NUMBER]
 -> GreaterEqual(Variable(age), 18)
 -> interpret({age:20}) = true

角色回答不能漏掉“谁构建 AST”;GoF 结构中的 Client 往往承担这一步,生产系统通常交给专门 Parser。

落地前可以再按下面 3 步复核:

  1. 先说明“Client/Parser”的核心机制:把输入构造成表达式树;再交代边界:处理语法结构。
  2. 接着分析“Expression”:实现解释契约;不能遗漏对应代价或结果:递归计算语义。
  3. 最后用“Context”检查方案:提供 age=20 等运行数据;验收时确认与 AST 分离。

这三项构成完整判断链:先讲清Client/Parser,再说明Expression,最后用Context检验实现是否越界。

面试中若能给出违反“与 AST 分离”的反例,再说明修正办法,答案就从模式定义落到了可验证的工程决策。

七、常见误区与追问

  • 误区:只看到“Client/Parser”就认为方案成立。 必须同时说明核心机制“把输入构造成表达式树”和工程边界“处理语法结构”。
  • 误区:把“Expression”当成无条件结论。 只有在“实现解释契约”成立时,才能据此讨论“递归计算语义”。
  • 追问:AbstractExpression 一定是抽象类吗? 不一定,Java 中常用接口表达统一 interpret 契约。
  • 追问:Parser 属于经典五角色吗? 经典图常由 Client 构建语法树,但工程上通常显式拆出 Parser。
  • 追问:谁处理语法错误? 解析阶段负责报告非法 token、缺失括号等语法错误。
  • 追问:谁处理变量不存在? 解释阶段通过 Context 查找并返回错误或采用明确默认策略。
  • 追问:AST 能否复用? 可以,同一不可变 AST 可配不同 Context 多次求值。

八、加强记忆

记忆时抓住这条主线:Expression 定义解释接口;终结符是叶子,非终结符是组合节点;Context 保存外部变量;执行过程通常是表达式树递归解释。面试回答先给出模式意图,再用调用链或数据流说明角色协作,最后主动交代适用边界与工程代价。