解释器设计模式在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. 国际化和本地化:在多语言网站开发中,解释器设计模式可以用于处理本地化字符串和格式化,例如解析日期时间格式、数字格式等。这些解释器可以将特定的本地化规则应用于字符串和数据,以生成适合特定语言环境的文本。
相关推荐
蟾宫曲4 小时前
在 Vue3 项目中实现计时器组件的使用(Vite+Vue3+Node+npm+Element-plus,附测试代码)
前端·npm·vue3·vite·element-plus·计时器
秋雨凉人心4 小时前
简单发布一个npm包
前端·javascript·webpack·npm·node.js
liuxin334455664 小时前
学籍管理系统:实现教育管理现代化
java·开发语言·前端·数据库·安全
qq13267029404 小时前
运行Zr.Admin项目(前端)
前端·vue2·zradmin前端·zradmin vue·运行zradmin·vue2版本zradmin
ke_wu4 小时前
结构型设计模式
开发语言·设计模式·组合模式·简单工厂模式·工厂方法模式·抽象工厂模式·装饰器模式
小马爱打代码4 小时前
设计模式详解(建造者模式)
java·设计模式·建造者模式
小王爱吃月亮糖4 小时前
C++的23种设计模式
开发语言·c++·qt·算法·设计模式·ecmascript
_im.m.z5 小时前
【设计模式学习笔记】1. 设计模式概述
笔记·学习·设计模式
魏时烟5 小时前
css文字折行以及双端对齐实现方式
前端·css
哥谭居民00016 小时前
将一个组件的propName属性与父组件中的variable变量进行双向绑定的vue3(组件传值)
javascript·vue.js·typescript·npm·node.js·css3