解释器设计模式在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. 国际化和本地化:在多语言网站开发中,解释器设计模式可以用于处理本地化字符串和格式化,例如解析日期时间格式、数字格式等。这些解释器可以将特定的本地化规则应用于字符串和数据,以生成适合特定语言环境的文本。
相关推荐
小中12344 分钟前
异步请求的性能提升
前端
我是天龙_绍5 分钟前
渐变层生成器——直接用鼠标拖拽就可以调整渐变层的各种参数,然后可以导出为svg格式
前端
我是天龙_绍33 分钟前
Easing 曲线 easings.net
前端
知识分享小能手36 分钟前
微信小程序入门学习教程,从入门到精通,电影之家小程序项目知识点详解 (17)
前端·javascript·学习·微信小程序·小程序·前端框架·vue
訾博ZiBo38 分钟前
React组件复用导致的闪烁问题及通用解决方案
前端
Dever40 分钟前
记一次 CORS 深水坑:开启 withCredentials 后Response headers 只剩 content-type
前端·javascript
临江仙45542 分钟前
流式 Markdown 渲染在 AI 应用中的应用探秘:从原理到优雅实现
前端·vue.js
Hilaku1 小时前
为什么我开始减少逛技术社区,而是去读非技术的书?
前端·javascript·面试
m0_728033131 小时前
JavaWeb——(web.xml)中的(url-pattern)
xml·前端
猪哥帅过吴彦祖1 小时前
第 8 篇:更广阔的世界 - 加载 3D 模型
前端·javascript·webgl