urlname
type
Post
password
SyncToConfluence
category
业务技能
date
Apr 2, 2025
slug
589e947f-99f3-4ee8-9aa2-1bd6e1b1999b
icon
Button
catalog
summary
tags
学习笔记
专业能力
设计模式
编程基础
cover
Status
BusyTime
Status 1
status
Published

什么是解释器模式(Interpreter Pattern)

解释器模式给定一种语言,定义它的文法表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
想象一下你要计算一个简单的数学表达式,比如 "5 + 2 - 3"。解释器模式就像是:
  1. 首先,为这种简单的加减法语言定义一套规则(文法):数字是基本元素(Terminal),加号和减号是运算(Non-terminal),运算连接两个表达式。
  1. 然后,构建一个能理解这些规则的解释器。这个解释器可以将字符串 "5 + 2 - 3" 转换成一个内部结构(通常是抽象语法树 - AST),比如一个表示减法的节点,它的左边是表示加法的节点(子节点是 5 和 2),右边是数字 3。
  1. 最后,解释器可以“执行”这个结构,计算出最终结果 4。
解释器模式的核心在于为一种简单的语言或领域特定语言 (DSL) 构建一个解析器和解释器。

核心思想

解释器模式通常涉及以下角色来构建和解释抽象语法树 (AST):
  1. 抽象表达式 (AbstractExpression): 定义一个抽象的 interpret() 操作接口,所有的终结符和非终结符表达式都要实现这个接口。这个方法通常接收一个上下文 (Context) 对象作为参数,用于存储解释过程中可能需要的全局信息(如变量的值)。
  1. 终结符表达式 (TerminalExpression):
      • 实现 AbstractExpression 接口。
      • 代表文法中的基本元素(终结符),比如数字、变量名。
      • 它的 interpret() 方法通常直接返回其代表的值,可能需要从 Context 中获取。
  1. 非终结符表达式 (NonterminalExpression):
      • 实现 AbstractExpression 接口。
      • 代表文法中的组合规则,比如加法、减法、逻辑运算等。
      • 它通常包含对其他 AbstractExpression 对象(子节点)的引用。
      • 它的 interpret() 方法会递归地调用其子表达式的 interpret() 方法,并根据自身的规则组合结果。
  1. 上下文 (Context): (可选但常见) 包含解释器在解释过程中需要访问的全局信息,例如变量的值映射。它被传递给各个表达式的 interpret() 方法。
  1. 客户端 (Client):
      • 负责构建(或获取)代表特定语句的抽象语法树 (AST)。注意:解释器模式本身不关心如何构建 AST,这通常由单独的解析器完成。
      • 创建一个 Context 对象(如果需要)。
      • 调用 AST 根节点的 interpret() 方法,启动解释过程。

优点

  1. 易于改变和扩展文法: 由于文法规则被表示为独立的类,添加新的文法规则(即新的非终结符或终结符表达式)相对容易,符合开闭原则(对扩展开放)。
  1. 实现简单: 对于简单的文法,实现解释器模式相对直接,每个类对应一个文法规则。
  1. 代码清晰: 文法规则的表示直观,易于理解。

可能的缺点

  1. 难以维护复杂文法: 对于复杂的文法,需要定义大量的类,这会导致类的数量急剧增加,使得系统难以管理和维护。
  1. 性能问题: 解释器模式通常效率不高,因为解释过程涉及大量的类创建和递归调用。对于性能要求高的场景不适用。
  1. 对解析器的依赖: 模式本身不关注如何将输入文本解析成 AST,这通常需要一个独立的、可能很复杂的解析器(Parser)。
  1. 使用场景有限: 主要适用于定义和解释简单的、结构化的语言或规则。

使用场景

解释器模式的应用相对比较窄,通常用于以下情况:
  1. 当有一个语言需要解释执行,并且你可以表示该语言的文法为抽象语法树时。
  1. 当语言的文法相对简单,效率不是关键问题时。
  1. 领域特定语言 (DSL): 为特定领域创建的简单语言,如配置文件解析、简单查询语言、模板引擎中的表达式等。
  1. 数学表达式求值: 如加减乘除、逻辑运算等。
  1. 正则表达式引擎 (概念上): 正则表达式本身是一种小语言,其匹配过程可以看作是对其文法树的解释。
  1. SQL 解析和执行 (简化版): 简单的 SQL 查询解析和执行引擎。
  1. Android 中的场景 (非常罕见):
      • 在典型的 Android 应用开发(UI、网络、数据存储)中,很少直接使用解释器模式。我们通常使用现成的库来处理需要解析的语言(如 JSON、XML、Protocol Buffers)。
      • 可能会在一些高度定制化的场景中出现,例如:
        • 应用内需要执行用户定义的简单脚本或规则
        • 为应用的特定功能设计一个非常简单的查询或过滤语言
        • 开发工具或特定框架内部可能用到。
      • 但对于任何稍微复杂的语言解析需求,通常会选择使用更成熟的解析器生成工具(如 ANTLR)或脚本语言引擎(如 JavaScript V8、Lua)。

UML 图

下面是基于“简单数学表达式求值 (加减法)”示例的解释器模式 UML 图:
  • Context: 存储变量名到其整数值的映射。
  • Expression (AbstractExpression): 定义 interpret 接口。
  • NumberExpression (TerminalExpression): 代表一个数字,interpret 直接返回值。
  • VariableExpression (TerminalExpression): 代表一个变量,interpret 从 Context 中查找值。
  • AddExpression, SubtractExpression (NonterminalExpression): 代表加法和减法。它们持有左右操作数(子 Expression),interpret 方法递归调用子表达式的 interpret 并执行相应的运算。
  • Client: 构建 AST(这里假设手动构建),创建 Context,并调用根节点的 interpret。

代码示例

在这个例子中:
  • Expression 是抽象表达式接口。
  • NumberExpression 和 VariableExpression 是终结符表达式。
  • AddExpression 和 SubtractExpression 是非终结符表达式,它们递归地调用子表达式的 interpret 方法。
  • EvaluationContext 存储变量的值。
  • 客户端代码手动构建了表示 "w + x - y" 和 "100 - (x + y)" 的 AST,设置了上下文中的变量值,然后调用根节点的 interpret 方法来计算结果。

总结

  • 解释器模式通过构建抽象语法树 (AST) 并定义解释操作,来处理简单的语言或文法
  • 它将文法规则映射到,使得对简单文法的扩展相对容易。
  • 主要缺点在于难以处理复杂文法(导致类爆炸和维护困难)以及潜在的性能问题
  • 在现代软件开发中,尤其是 Android 应用开发中,其应用场景非常有限,通常会被更强大的解析工具或库所取代。
💡
记住它的核心:定义小语言,规则变成类,递归解释 AST 把活干。但语言一复杂,这招就不好玩。
设计模式——创建型-原型模式设计模式——行为型模式-访问者模式
Loading...