解释器设计模式在Js中的使用

📒解释器模式(Interpreter Pattern)

🏷定义:

一种行为型设计模式,用于定义一个语言的文法,并解释该语言中的表达式。

它将每个文法规则 表示为一个类,通过组合这些规则的对象来解释表达式。

🍔参与者:

  1. 抽象表达式(Abstract Expression):定义了一个抽象接口,声明了解释操作的方法。
  2. 终结符表达式(Terminal Expression):实现了抽象表达式接口,表示语言中的终结符或基本表达式。
  3. 非终结符表达式(Non-terminal Expression):实现了抽象表达式接口,表示语言中的非终结符或复杂表达式。通常由多个终结符和/或其他非终结符组成。
  4. 上下文(Context):包含需要解释的语句或表达式。
  5. 解释器:调用终结符和非终结符处理上下文对象,并返回解释结果或者根据结果执行动作。

🍍使用流程:

  1. 定义表达式的文法规则,并将其表示为抽象表达式、终结符表达式和非终结符表达式。
  2. 创建上下文对象 ,并将需要解释的语句或表达式传递给上下文。
  3. 根据语言的文法规则,逐步解释表达式。在解释器的实现中,根据不同的终结符和非终结符进行相应的处理和计算。
  4. 客户端通过调用解释器 来执行和处理表达式,并获取最终的结果

🍕 优点:

  • 可以简化复杂语言的解析和执行过程,提供了一种灵活且可扩展的方式来定义新的语法规则;
  • 可以将语言的表达式表示为类层次结构 ,使代码更易于理解和维护
  • 支持动态添加新的解释器,从而增加语言的功能和灵活性。

🍃 缺点:

  • 处理复杂的语法规则可能会导致类层次结构庞大,难以管理和维护。
  • 解释器的执行效率可能较低,特别是对于大型、复杂的表达式。

🥞 示例:

typescript 复制代码
// 抽象表达式类
abstract class Expression {
  abstract interpret(context: Context): any;
}

class Context {
  constructor(public data: string) {}
}

// 终结符表达式类:获取运算第一个数字
class GetNum1 extends Expression {
  interpret(context: Context) {
    const { data } = context;
    const match = /如果(\d+)/.exec(data);
    const num1 = match[1] - 0;
    return num1;
  }
}

// 终结符表达式类:获取运算第二个数字
class GetNum2 extends Expression {
  interpret(context: Context) {
    const { data } = context;
    const match = /(\d+)等于/.exec(data);
    const num2 = match[1] - 0;
    return num2;
  }
}

// 终结符表达式类:获取运算计算结果
class GetRst extends Expression {
  interpret(context: Context) {
    const { data } = context;
    const match = /等于(\d+)/.exec(data);
    const rst = match[1] - 0;
    return rst;
  }
}

// 终结符表达式类:获取收信人
class GetTarget extends Expression {
  interpret(context: Context) {
    const { data } = context;
    const match = /发信息给(.*?)!/.exec(data);
    const target = match[1];
    return target;
  }
}

// 终结符表达式类:获取运算符
class GetOperator extends Expression {
  interpret(context: Context) {
    const { data } = context;
    const match = /如果\d+(.*?)\d+等于/.exec(data);
    const oper = match[1].trim();
    return oper;
  }
}

// 解释器类
class Interpretor extends Expression {
  constructor(
    public getNum1: GetNum1,
    public getNum2: GetNum2,
    public getRst: GetRst,
    public getOper: GetOperator,
    public getTarget: GetTarget
  ) {
    super();
  }

  interpret(context: Context) {
    const num1 = this.getNum1.interpret(context);
    const num2 = this.getNum2.interpret(context);
    const rst = this.getRst.interpret(context);
    const oper = this.getOper.interpret(context);
    const target = this.getTarget.interpret(context);
    let valid = false;

    switch (oper) {
      case "+":
        valid = Math.abs(num1 + num2 - rst) < 1e-4;
        break;
      case "-":
        valid = Math.abs(num1 - num2 - rst) < 1e-4;
        break;
      case "*":
        valid = Math.abs(num1 * num2 - rst) < 1e-4;
        break;
      case "/":
        valid = Math.abs(num1 / num2 - rst) < 1e-4;
        break;
    }

    if (valid) {
      console.log(`信息正确,将结果${rst}发送给收件人${target}`);
    } else {
      console.log(`信息错误,结果不会发送给收件人${target}`);
    }
    // 返回解释器翻译结果
    return {
      num1,
      num2,
      rst,
      oper,
      target,
    };
  }
}

// 使用示例
// 创建上下文实例对象
const context1 = new Context("如果10-3等于7,发信息给张三!");
const context2 = new Context("如果1 *2等于7,发信息给李四!");
// 创建终结符表达式类
const getNum1 = new GetNum1();
const getNum2 = new GetNum2();
const getRst = new GetRst();
const getOper = new GetOperator();
const getTarget = new GetTarget();
// 创建解释器实例
const interpretor = new Interpretor(
  getNum1,
  getNum2,
  getRst,
  getOper,
  getTarget
);
// 使用解释器实例对象解释上下文对象
interpretor.interpret(context1);
interpretor.interpret(context2);
/*
>>>
信息正确,将结果7发送给收件人张三
信息错误,结果不会发送给收件人李四
*/

🥗 使用场景:

  1. 解析和执行脚本语言:浏览器通过 JavaScript 解释器来解析和执行 JavaScript 代码。这个解释器可以被视为实现了解释器设计模式的一部分,它将 JavaScript 代码转换成可执行的指令。
  2. 正则表达式:在 JavaScript 中,正则表达式是一种强大的工具,它通常用于匹配、搜索和替换文本。正则表达式可以被看作是一种小型的解释器,它解释并执行特定的模式规则。
  3. 数据查询和处理语言:在浏览器开发中,我们经常使用像 XPath、CSS 选择器或 jQuery 等工具来查询和操作 DOM 元素。这些查询语言可以被视为解释器,它们解释和执行特定的查询语句,并返回符合条件的结果集。
  4. 模板引擎:模板引擎用于生成动态内容,例如在前端开发中根据数据渲染 HTML 模板。一些模板引擎(如 Handlebars、Mustache 等)可能使用解释器设计模式,将模板语法解释为可执行的代码块。
  5. 国际化和本地化:在多语言网站开发中,解释器设计模式可以用于处理本地化字符串和格式化,例如解析日期时间格式、数字格式等。这些解释器可以将特定的本地化规则应用于字符串和数据,以生成适合特定语言环境的文本。
相关推荐
mldong5 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排5 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60616 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角7 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!7 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰7 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi9 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen9 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马10 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu10 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss