解释器模式通过构建AST解析业务规则,核心角色包括抽象表达式、终结符/非终结符表达式和上下文,支持动态变量、嵌套属性及安全扩展。

规则字符串先转成抽象语法树(AST)
用户输入的规则不是直接执行的,得先“读懂”它。比如输入:
"age > 18 AND gender == '男'"
需要经过词法分析(切出 age、>、18、AND、gender、==、'男')和语法分析(识别出这是两个比较条件用 AND 连接),最终构建成一棵树:根节点是 AndExpression,左子树是 GreaterExpression(age > 18),右子树是 EqualExpression(gender == '男')。这棵树就是 AST —— 所有后续解释都基于它。
四类角色各司其职
解释器模式靠四个关键角色协作:
-
抽象表达式(Expression):定义统一接口,比如
boolean interpret(Context context),所有具体表达式都实现它 - 终结符表达式(如 VariableExpression、NumberExpression、StringLiteralExpression):对应最小不可分单元。VariableExpression 负责从上下文里取 age 的值;StringLiteralExpression 返回 “男” 字符串
- 非终结符表达式(如 GreaterExpression、EqualExpression、AndExpression):负责组合与运算。AndExpression 会调用左右子表达式的 interpret 方法,再做逻辑与
-
上下文(Context):存运行时数据,比如当前用户对象、变量映射表(
Map<string object></string>)。解释过程中所有取值操作都通过它完成
支持变量和动态值的关键在于 Context
真实业务中规则很少只含常量。比如规则 “score >= threshold AND status == active”,threshold 和 active 都要从外部传入。这时 Context 就不只是存储数字或字符串,而是一个带作用域的容器:
- 初始化时把当前用户、配置参数、系统时间等注入 Context
- VariableExpression 在 interpret 时调用
context.get("threshold")获取实时值 - 支持嵌套属性访问(如 user.age)可通过反射或 SpEL 风格路径解析增强 Context 能力
扩展新规则只需加新类,不动原有代码
当业务新增 “IN” 操作(如 role IN ['admin', 'editor'])时,不需要改已有逻辑:
立即学习“Java免费学习笔记(深入)”;
- 新增一个 InExpression 类,实现 Expression 接口
- 它的 interpret 方法接收 Context,取出 role 值和右侧字符串列表,做包含判断
- 语法分析器识别到 IN 关键字时,就构造 InExpression 节点并挂到 AST 对应位置
- 整个流程对 AddExpression、AndExpression 等完全透明
实际落地要注意的细节
纯理论模型容易忽略工程现实:
- 字符串解析部分(词法+语法)可用 JavaCC、ANTLR,或轻量级手写递归下降解析器,避免正则硬匹配带来的维护难题
- 避免过度创建对象:频繁调用规则时,考虑复用 Expression 实例或引入缓存机制
- 错误提示要友好:解析失败时给出具体位置(第几行第几个字符)和预期 token,方便业务人员调试规则
- 安全边界必须设好:禁止执行任意方法调用(如 user.getClass().forName(...)),只允许白名单内的字段访问和基础运算


















