设计模式之解释器模式的魅力:让代码读懂你的语言

目录

一、什么是解释器模式

二、解释器模式的应用场景

三、解释器模式的优缺点

3.1. 优点

3.2. 缺点

四、解释器模式示例

4.1. 问题描述

4.2. 问题分析

4.3. 代码实现

4.4. 优化方向

五、总结


一、什么是解释器模式

    解释器模式(Interpreter pattern)是一种行为型(Behavioral Pattern)的设计模式,用于定义语言的语法规则表示,并提供解释器来处理句子中的语法。该模式将句子表示为一个抽象语法树,每个节点代表一个语法规则,通过递归地解释这些节点来实现对句子的解释。

    解释器模式主要包含以下五类角色:

  • 抽象表达式(Abstract Expression):定义了解释器的接口,包括一个解释方法,并根据文法规则解释表达式。
  • 终结符表达式(Terminal Expression):实现抽象表达式接口,代表文法中的终结符。
  • 非终结符表达式(Non-Terminal Expression):实现抽象表达式接口,代表文法中的非终结符,通常包含其他表达式。
  • 上下文(Context):包含需要被解释的信息或状态,解释器通过上下文来执行解释操作。
  • 客户端(Client):创建和配置具体的解释器表达式,构建解释器的抽象语法树,并调用解释器的解释方法来解释表达式。

    解释器模式的结构如下所示:

二、解释器模式的应用场景

    解释器模式适用于需要解释和执行特定领域语言的场景,常见的适合应用解释器模式的场景包括但不限于:

  • 编程语言解释器:解释器模式最经典的应用就是编程语言的解释器。例如,Python、JavaScript等编程语言都使用解释器来解释和执行代码。
  • 数学表达式解析:解释器模式可以用于解析和计算数学表达式。例如,我们可以使用解释器模式来解析并计算一个复杂的数学公式。
  • 查询语言解析:解释器模式可以用于解析和执行查询语言。例如,数据库查询语言的解析和执行就可以使用解释器模式来实现。

三、解释器模式的优缺点

3.1. 优点

    1)可扩展性:增加新的解释表达式比较方便,扩展时不需要修改原有的逻辑,符合开闭原则。

    2)灵活性:改变或扩展文法都比较容易。

    3)实现文法容易:语法树中的每个表达式节点类都是相似的,易于实现。

3.2. 缺点

    1)类膨胀:每个语法都要产生一个非终结符表达式,可能导致大量类文件。

    2)性能问题:递归解释语法可能导致效率低下。

四、解释器模式示例

4.1. 问题描述

    为了更好地理解解释器模式的应用,我们将以一个简单的例子来演示它的实现过程。假设我们需要设计一个简单的计算器,能够解析并计算用户输入的包含加减乘除四种计算的数学表达式,其中只存在数字和加(+)、减(-)、乘(*)、除(/)四种符号,每种元素之间以空格区分,并且四种运算符号的运算顺序总是从左到右的(即不限定一定要先算乘除后算加减)。

4.2. 问题分析

    我们以一个简单的表达式“2 + 3 * 4 - 5 / 3”为例,其语法树可以表示为:

    其中包含一种终结符表达式(数字表达式)以及四种非终结符表达式(加减乘除四种表达式)。则我们可以:

    1)定义一个抽象表达式接口(AbstractExpression),并包含一个解释方法interpret()用于返回解释结果。

    2)定义一个数字表达式类(NumberExpression),它的内部维护了一个数字对象,并且其实现的interpret()方法直接返回这个数字对象。

    3)为加减乘除四种运算规则分别定义相应的表达式类(AddExpression,SubExpression,MulExpression,DivExpression),它们的内部都维护了AbstractExpression类型的运算的左值(left)和右值(right),并分别按照各自的规则实现interpret()方法返回运算结果。

    4)由于此计算器只需要从左往右顺序地计算下来就可以了,所以表达式中并不需要知道上下文环境,那么我们可以省略定义上下文类(Context),而直接定义客户端类(Client)用于对外提供运算接口(execute(String exp)),将接收到的表达式字符串参数转换成使用解释器对象描述的语法树,并解释并输出解释结果。

4.3. 代码实现

    经过上一步的分析之后,下面我们通过代码来实现它:

interface AbstractExpression{public int interpret();
}
​
class NumberExpression implements AbstractExpression{private int number;
​NumberExpression(int number) {this.number = number;}
​@Overridepublic int interpret() {return number;}
}
//加法
class AddExpression implements AbstractExpression{private AbstractExpression left;private AbstractExpression right;
​AddExpression(AbstractExpression left, AbstractExpression right) {this.left = left;this.right = right;}
​@Overridepublic int interpret() {return left.interpret() + right.interpret();}
}
//减法
class SubExpression implements AbstractExpression{private AbstractExpression left;private AbstractExpression right;
​SubExpression(AbstractExpression left, AbstractExpression right) {this.left = left;this.right = right;}
​@Overridepublic int interpret() {return left.interpret() - right.interpret();}
}
//乘法
class MulExpression implements AbstractExpression{private AbstractExpression left;private AbstractExpression right;
​MulExpression(AbstractExpression left, AbstractExpression right) {this.left = left;this.right = right;}
​@Overridepublic int interpret() {return left.interpret() * right.interpret();}
}
//除法
class DivExpression implements AbstractExpression{private AbstractExpression left;private AbstractExpression right;
​DivExpression(AbstractExpression left, AbstractExpression right) {this.left = left;this.right = right;}
​@Overridepublic int interpret() {return left.interpret() / right.interpret();}
}
​
class Cient{public int execute(String exp){String[] elements = exp.split(" ");if(elements.length % 2 == 0){throw new RuntimeException("表达式错误");}AbstractExpression expression = new NumberExpression(Integer.parseInt(elements[0]));for (int i = 1; i < elements.length-1; i+=2) {String symbol =  elements[i];int num;try{num = Integer.parseInt(elements[i+1]);}catch (NumberFormatException e){throw new RuntimeException("表达式错误");}if (symbol.equals("+")){expression = new AddExpression(expression, new NumberExpression(num));}else if (symbol.equals("-")){expression = new SubExpression(expression, new NumberExpression(num));}else if (symbol.equals("*")){expression = new MulExpression(expression, new NumberExpression(num));}else if (symbol.equals("/")){expression = new DivExpression(expression, new NumberExpression(num));}else {System.out.println("无效的符号");}}return expression.interpret();}
}

    接下来编写测试类:

    public static void main(String[] args) {Cient cient = new Cient();System.out.println(cient.execute("2 + 3 * 4 - 5 / 3"));System.out.println(cient.execute("5 * 2 + 9 - 1 / 6"));System.out.println(cient.execute("5 / 5 + 1 / 1 * 10 - 1"));}

    测试结果为:

        测试通过! 

4.4. 优化方向

    作为一个开发人员,完成一段代码功能之后当然要不断反思自己的代码还有哪些不足,就以上示例而言,针对使用者有可能的千奇百怪的输入来说,首先这段代码的异常捕获和提示内容就是不足的,当然,仅仅用来作为说明解释器模式的实例来讲,我们的目的已经达到了,所以这里不再多做补充(不是因为懒~)。另外,如果我们学习过其他设计模式,我们可以将解释器模式和其他设计模式结合使用,而达到进一步优化的目的,比如我们可以用组合模式来构建语法树,用工厂模式来创建不同类型的表达式,而如何通过代码来实现它们,就要涉及其他设计模式的说明了,本文暂不做赘述(那肯定也不是因为懒~)

五、总结

    解释器模式是一种强大而有趣的设计模式,它可以帮助我们简化复杂问题的处理过程。通过定义文法规则、创建抽象语法树和实现解释器,我们可以轻松地解释和执行特定语言的句子。希望本文对你理解解释器模式有所帮助,能够在实际开发中灵活运用!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/781922.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kubernetes(K8S)学习(七):K8S之系统核心组件

K8S之系统核心组件 K8s系统核心组件1.1 Master和Node1.2 kubeadm1.3 先把核心组件总体过一遍1.4 Kubernetes源码查看方式1.5 kubectl1.6 API Server1.7 集群安全机制之API Server1.8 Scheduler1.9 kubelet1.10 kube-proxy K8s系统核心组件 1.1 Master和Node 官网 &#xff1a;…

360奇酷刷机 360刷机助手 QGDP360手机QGDP刷机

360奇酷刷机 360刷机助手 QGDP破解版360手机QGDP刷机 360手机刷机资源下载链接&#xff1a;360rom.github.io 参考&#xff1a;360手机-360刷机360刷机包twrp、root 360奇酷刷机&#xff1a;360高通驱动安装 360手机刷机驱动&#xff1b;手机内置&#xff0c;可通过USB文件传输…

搜索与图论——染色法判定二分图

一个图是二分图当且仅当这个图中不含奇数环 由于图中没有奇数环&#xff0c;所以染色过程中一定没有矛盾 所以一个二分图一定可以成功被二染色&#xff0c;反之在二染色的过程中出现矛盾的图中一定有奇数环&#xff0c;也就一定不是二分图 #include<iostream> #includ…

【c++初阶】类与对象(中)

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ &#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1…

Transformer论文阅读

Transformer论文阅读 摘要结论1 Introduction &#xff08;导言&#xff09;2 Background3 Model Architecture3.1 Encoder and Decoder StacksEncoderLayer NormDecoder 3.2 Attention3.2.1 Scaled Dot-Product Attention3.2.2 Scaled Dot-Product Attention3.2.3 Application…

4月1日起,未备案App小程序将下架

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 最后2天了、最后2天了。 从2024年4月1日起&#xff0c;工信部要求所有的APP、小程序都要备案&#xff0c;否则下架、关停、限制更新。这是去年8月份出的新规&#xff0c;没想到十个月这么快就过去了。 现在广东省…

深入解析大语言模型显存占用:训练与推理

深入解析大语言模型显存占用&#xff1a;训练与推理 文章脉络 估算模型保存大小 估算模型在训练时占用显存的大小 全量参数训练 PEFT训练 估算模型在推理时占用显存的大小 总结 对于NLP领域的从业者和研究人员来说&#xff0c;有没有遇到过这样一个场景&#xff0c;你的…

某东推荐的十大3C热榜第一名!2024随身wifi靠谱品牌推荐!2024随身wifi怎么选?

一、鼠标金榜&#xff1a;戴尔 商务办公有线鼠标 售价:19.9&#xffe5; 50万人好评 二、平板电脑金榜&#xff1a;Apple iPod 10.2英寸 售价:2939&#xffe5; 200万人好评 三、随身WiFi金榜&#xff1a;格行随身WiFi 售价:69&#xffe5; 15万人好评 四、游戏本金榜&#xff…

Gromacs模拟一:配体-双链蛋白质复合物体系准备

1、蛋白质的准备&#xff1a; 在RCSB网站下载想要的蛋白晶体&#xff08;教程里是3htb&#xff09;&#xff0c;用notepad等编辑器或是分子可视化软件除去里面的非蛋白分子或离子。 这里采用的是一个经过分子对接后的蛋白质pdb和配体小分子的pdb。 教程里提到的配体是2-丙基…

【Java多线程】5——Lock底层原理

5 Lock底层原理 ⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记仓库&#x1f449;https://github.com/A-BigTree/tree-learning-notes 个人主页&#x1f449;https://www.abigtree.top ⭐⭐⭐⭐⭐⭐ 如果可以&#xff0c;麻烦各位看官顺手点个star~&…

新能源汽车充电桩常见类型及充电桩站场的智能监管方案

随着新能源汽车市场的迅猛发展&#xff0c;充电桩作为支持其运行的基础设施&#xff0c;也呈现出多样化的类型。这些充电桩不仅在外形和功能上存在差异&#xff0c;更在充电速度、充电方式以及使用场景等方面展现出独特的优势。 一、充电桩类型及区别 1、慢充桩&#xff08;交…

Go 之 Gin 框架

Gin 是一个 Go (Golang) 编写的轻量级 web 框架&#xff0c;运行速度非常快&#xff0c;擅长 Api 接口的高并发&#xff0c;如果项目的规模不大&#xff0c;业务相对简单&#xff0c;这个时候我们也推荐您使用 Gin&#xff0c;特别适合微服务框架。 简单路由配置 package mai…

Linux 系统快速安装 nginx (新手版)

1、安装所需依赖 yum -y install pcre pcre-devel gcc openssl openssl-devel zlib zlib-devel &#xff08;pcre&#xff1a; 包括 perl 兼容的正则表达式库 openssl&#xff1a; 支持安全传输协议https(和财务有关系的请求会走的协议) 创建运行用户、组 useradd -M -…

变分信息瓶颈

变分信息瓶颈和互信息的定义 1 变分信息瓶颈 定义&#xff1a;变分信息瓶颈&#xff08;Variational Information Bottleneck&#xff09;是一种用于学习数据表示的方法&#xff0c;它旨在通过最小化输入和表示之间的互信息来实现数据的压缩和表示学习。这种方法通常用于无监…

Oracle VM(虚拟机)性能监控工具

Oracle VM是一个独立的虚拟化环境&#xff0c;由 Oracle 提供支持和设计&#xff0c;旨在为运行虚拟机提供轻量级、安全的基于服务器的平台。Oracle VM 能够在受支持的虚拟化环境中部署操作系统和应用软件&#xff0c;Oracle VM 将用户和管理员与底层虚拟化技术隔离开来&#x…

ctfshow xxe web373-378

web373 libxml_disable_entity_loader(false)&#xff1a;这行代码用于启用实体加载器&#xff0c;允许加载外部实体。 $xmlfile file_get_contents(php://input)&#xff1a;从输入流中读取XML数据并存储在 $xmlfile 变量中。 $dom->loadXML($xmlfile, LIBXML_NOENT |…

FebHost:意大利.IT域名一张意大利网络名片

.IT域名是意大利的国家顶级域名&#xff0c;对于意大利企业和个人而言,拥有一个属于自己的”.IT”域名无疑是件令人自豪的事。这个被誉为意大利互联网标志性代表的域名,不仅隐含着浓厚的意大利文化特色,还为使用者在当地市场的推广铺平了道路。 对于那些希望在意大利市场建立强…

微信开发者工具接入短剧播放器插件

接入短剧播放插线 申请添加插件基础接入app.jsonapp.jsplayerManager.js数据加密跳转到播放器页面运行出错示例小程序页面页面使用的方法小程序输入框绑定申请添加插件 添加插件:登录微信开发者平台 ——> 设置 ——> 第三方设置 ——> 插件管理 ——> 搜索“短剧…

基于SpringBoot + Vue实现的养老院管理系统设计与实现+毕业论文(12000字)+搭建视频

介绍 养老院管理系统是一款运用软件开发技术设计实现的应用系统&#xff0c;在信息处理上可以达到快速的目的&#xff0c;不管是针对数据添加&#xff0c;数据维护和统计&#xff0c;以及数据查询等处理要求&#xff0c;养老院管理系统都可以轻松应对。 系统包含登录、注册、…

Linux 系统 docker搭建LNMP环境

1、安装nginx docker pull nginx (默认安装的是最新版本) 2、运行nginx docker run --name nginx -p 80:80 -d nginx:latest 备注&#xff1a;--name nginx 表示容器名为 nginx -d 表示后台运行 -p 80:80 表示把本地80端口绑定到Nginx服务端的 80端口 nginx:lates…