什么是解释器模式?

解释器模式(Interpreter Pattern)是一种行为型设计模式,它定义了一种语言的语法规则,并通过一个 “解释器” 来解释执行该语言中的句子(表达式)。

其核心思想是:将复杂的语法规则拆分为简单的 “终结符” 和 “非终结符”,通过递归组合这些符号,构建一个解释器来解析和执行表达式。这种模式适合处理简单的语法解析场景(如数学表达式计算、简单规则引擎)。

解释器模式的核心角色

  1. 抽象表达式(Abstract Expression):定义所有表达式的公共接口,声明解释方法(如 interpret(context))。
  2. 终结符表达式(Terminal Expression):表示语法中的不可再分的基本符号(如数字、变量),实现抽象表达式的解释方法。
  3. 非终结符表达式(Non-terminal Expression):表示语法中的组合符号(如运算符 +-),包含其他表达式(终结符或非终结符),通过递归解释子表达式完成自身逻辑。
  4. 上下文(Context):存储解释器需要的全局信息(如变量映射表),供表达式解释时使用。
  5. 客户端(Client):构建表达式树(语法树),调用解释方法执行表达式。

JavaScript 实现解释器模式示例:简单数学表达式解析

以下以 “加减数学表达式” 为例,实现解释器模式。场景是:解析并计算形如 1 + 2 - 3 的表达式,支持整数和 +- 运算符。

代码实现
// -------------- 1. 抽象表达式(Abstract Expression)--------------
class Expression {
  /**
   * 解释表达式并返回结果
   * @param {Context} context - 上下文对象
   * @returns {number} 计算结果
   */
  interpret(context) {
    throw new Error("子类必须实现 interpret 方法");
  }
}

// -------------- 2. 终结符表达式(Terminal Expression):数字 --------------
class NumberExpression extends Expression {
  constructor(value) {
    super();
    this.value = value; // 存储数字值(如 1、2)
  }

  // 解释:直接返回数字值
  interpret(context) {
    return this.value;
  }
}

// -------------- 3. 非终结符表达式(Non-terminal Expression):运算符 --------------
// 加法表达式
class AddExpression extends Expression {
  /**
   * @param {Expression} left - 左表达式(如 NumberExpression 或其他运算符表达式)
   * @param {Expression} right - 右表达式
   */
  constructor(left, right) {
    super();
    this.left = left;
    this.right = right;
  }

  // 解释:计算左表达式 + 右表达式的结果
  interpret(context) {
    return this.left.interpret(context) + this.right.interpret(context);
  }
}

// 减法表达式
class SubtractExpression extends Expression {
  constructor(left, right) {
    super();
    this.left = left;
    this.right = right;
  }

  // 解释:计算左表达式 - 右表达式的结果
  interpret(context) {
    return this.left.interpret(context) - this.right.interpret(context);
  }
}

// -------------- 4. 上下文(Context):存储全局信息(此处简单处理,无变量)--------------
class Context {
  constructor() {
    // 若支持变量,可在此存储 { 变量名: 值 } 的映射,如 { a: 10, b: 20 }
  }
}

// -------------- 5. 客户端工具:构建表达式树(语法解析器)--------------
class ExpressionParser {
  /**
   * 解析表达式字符串,构建表达式树
   * @param {string} expression - 表达式字符串(如 "1 + 2 - 3")
   * @returns {Expression} 根表达式(非终结符)
   */
  parse(expression) {
    // 分割表达式为 tokens(数字和运算符),如 ["1", "+", "2", "-", "3"]
    const tokens = expression.split(/\s+/);
    if (tokens.length === 0) {
      throw new Error("空表达式");
    }

    // 初始表达式为第一个数字
    let result = new NumberExpression(parseInt(tokens[0], 10));

    // 遍历后续 tokens,构建运算符表达式(左结合)
    for (let i = 1; i < tokens.length; i += 2) {
      const operator = tokens[i];
      const number = new NumberExpression(parseInt(tokens[i + 1], 10));

      switch (operator) {
        case "+":
          result = new AddExpression(result, number);
          break;
        case "-":
          result = new SubtractExpression(result, number);
          break;
        default:
          throw new Error(`不支持的运算符:${operator}`);
      }
    }

    return result;
  }
}

// -------------- 6. 客户端使用 --------------
// 创建上下文和解析器
const context = new Context();
const parser = new ExpressionParser();

// 解析并计算表达式
function calculate(expression) {
  const exprTree = parser.parse(expression);
  const result = exprTree.interpret(context);
  console.log(`${expression} = ${result}`);
}

// 测试表达式
calculate("1 + 2"); // 输出:1 + 2 = 3
calculate("5 - 3 + 4"); // 输出:5 - 3 + 4 = 6
calculate("10 - 2 - 3"); // 输出:10 - 2 - 3 = 5
calculate("7 + 8 - 5 + 2"); // 输出:7 + 8 - 5 + 2 = 12

代码说明

  1. 抽象表达式(Expression):定义 interpret 方法,所有具体表达式必须实现该方法来解释自身。

  2. 终结符表达式(NumberExpression)

    • 表示表达式中的数字(如 12),是语法中不可再分的基本单位。
    • interpret 方法直接返回自身存储的数字值,无需依赖其他表达式。
  3. 非终结符表达式(AddExpression、SubtractExpression)

    • 表示运算符(+-),包含左、右两个子表达式(可以是数字或其他运算符表达式)。
    • interpret 方法通过递归调用子表达式的 interpret 方法,获取子结果后执行自身运算(如加法、减法)。
  4. 上下文(Context):此处简化处理,未存储变量(若扩展支持变量,可在此存储变量名与值的映射,供表达式解析时查询)。

  5. 表达式解析器(ExpressionParser)

    • 负责将表达式字符串(如 "5 - 3 + 4")解析为表达式树(语法树)。
    • 解析逻辑:先分割字符串为 tokens(数字和运算符),再通过循环构建嵌套的运算符表达式(如 SubtractExpression(5, AddExpression(3, 4)))。
  6. 执行流程:客户端调用 calculate 时,先通过解析器构建表达式树,再调用根表达式的 interpret 方法,递归计算最终结果。

解释器模式的优势

  • 灵活性高:语法规则通过类的组合实现,新增语法(如乘法 *)只需添加新的非终结符表达式(MultiplyExpression),无需修改现有代码,符合 “开闭原则”。
  • 易于实现简单语法:对于简单语法(如示例中的加减运算),结构清晰,实现难度低。
  • 可扩展性:可通过上下文存储额外信息(如变量、函数),扩展表达式的功能(如支持 a + b 其中 a=10b=20)。

适用场景与局限性

  • 适用场景
    • 简单语法解析(如配置文件解析、数学表达式计算)。
    • 规则引擎(如简单的业务规则判断,如 (age > 18) && (score > 60))。
  • 局限性
    • 复杂语法会导致类爆炸(每个语法规则对应一个类),维护困难(如 SQL 解析不适合用解释器模式)。
    • 递归调用可能影响性能,不适合处理超长表达式。

解释器模式的核心是 “拆分语法,递归解释”,通过将语法规则映射为类的层次结构,实现对自定义语言的解析和执行。它适合处理简单、固定的语法场景,是构建小型解析器的有效方案。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐