Java 设计模式——解释器模式
目录
- 1.概述
- 2.结构
- 3.案例实现
- 3.1.抽象表达式类
- 3.2.终结表达式
- 3.3.非终结表达式
- 3.4.环境类
- 3.5.测试
- 4.优缺点
- 5.使用场景
1.概述
(1)如下图,设计一个软件用来进行加减计算。我们第一想法可能就是使用工具类,提供对应的加法和减法的工具方法。
//用于两个整数相加
public static int add(int a,int b){ return a + b;
}//用于两个整数相加
public static int add(int a,int b,int c){ return a + b + c;
}//用于 n 个整数相加(使用可变参数)
public static int add(Integer... arr) { int sum = 0; for (Integer i : arr) { sum += i; }return sum;
}
上面的形式比较单一、有限,如果形式变化非常多,这就不符合要求,因为加法和减法运算,两个运算符与数值可以有无限种组合方式。比如 1 + 2 + 3 + 4 + 5、1 + 2 + 3 - 4等等。显然,现在需要一种翻译识别机器,能够解析由数字以及 +、- 符号构成的合法的运算序列。如果把运算符和数字都看作节点的话,能够逐个节点的进行读取解析运算,这就是解释器模式的思维。
(2)解释器模式 (Interpreter pattern) 是一种行为型设计模式,用于表示一个语言文法的语法规则,以及如何解析和执行该语法规则。解释器模式将一个语言表达式表示为对象,并定义了解析该表达式的语法规则。它包含了一个抽象表达式类和具体的表达式类。解释器模式主要通过使用递归来实现计算过程,即通过调用表达式对象的解释方法来进行计算。它可以用于编译器、解释器、数学公式计算等领域。
(3)在解释器模式中,我们需要将待解决的问题,提取出规则,抽象为一种“语言”。比如加减法运算,规则为:由数值和 +、- 符号组成的合法序列,“1 + 3 - 2” 就是这种语言的句子。解释器就是要解析出来语句的含义。但是如何描述规则呢?
(4)文法/语法规则(用于描述语言的语法结构的形式规则):
expression ::= value | plus | minus
plus ::= expression '+' expression
minus ::= expression '-' expression
value ::= integer
注意: 这里的符号“::=”表示“定义为”的意思,竖线 | 表示或,左右的其中一个,引号内为字符本身,引号外为语法。上面规则描述为 :表达式可以是一个值,也可以是 plus 或者 minus 运算,而 plus 和 minus 又是由表达式结合运算符构成,值的类型为整型数。
(5)抽象语法树
在计算机科学中,抽象语法树 (Abstract Syntax Tree,AST),或简称语法树 (Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。用树形来表示符合文法规则的句子:
2.结构
解释器模式包含以下主要角色:
- 抽象表达式 (Abstract Expression) 角色:定义了一个抽象的接口,用于解析语法规则。通常它是一个抽象类或接口,其中包含了解释器需要实现的方法。。
- 终结符表达式 (Terminal Expression) 角色:终结符表达式是最基本的表达式,它代表语言中的一个基本单元,通常是一个具体的值或一个变量。
- 非终结符表达式 (Nonterminal Expression) 角色:非终结符表达式是由多个终结符表达式或其他非终结符表达式组成的复合表达式。
- 环境 (Context) 角色:环境对象包含了解析器运行所需要的全局信息。
- 客户端 (Client) 角色:客户端用于创建解释器并调用其解释方法来解析语法规则。
3.案例实现
【例】设计实现加减法的软件
具体实现代码如下:
3.1.抽象表达式类
AbstractExpression.java
//抽象表达式类
public abstract class AbstractExpression {public abstract int interpret(Context context);
}
3.2.终结表达式
Variable.java
//用于封装变量的类
public class Variable extends AbstractExpression{//声明存储变量名的成员变量private String name;public Variable(String name) {this.name = name;}@Overridepublic int interpret(Context context) {//直接返回变量的值return context.getValue(this);}@Overridepublic String toString() {return name;}
}
3.3.非终结表达式
Plus.java
//加法表达式类
public class Plus extends AbstractExpression{// + 左边的表达式private AbstractExpression left;// + 右边的表达式private AbstractExpression right;public Plus(AbstractExpression left, AbstractExpression right) {this.left = left;this.right = right;}@Overridepublic int interpret(Context context) {//将左边表达式的结果和右边的进行相加return left.interpret(context) + right.interpret(context);}@Overridepublic String toString() {return "(" + left.toString() + "+" + right.toString() + ")";}
}
Minus.java
//减法表达式类
public class Minus extends AbstractExpression{// - 左边的表达式private AbstractExpression left;// - 右边的表达式private AbstractExpression right;public Minus(AbstractExpression left, AbstractExpression right) {this.left = left;this.right = right;}@Overridepublic int interpret(Context context) {//将左边表达式的结果和右边的进行相减return left.interpret(context) - right.interpret(context);}@Overridepublic String toString() {return "(" + left.toString() + "-" + right.toString() + ")";}
}
3.4.环境类
Context.java
//环境角色类
public class Context {//定义一个 map 集合,用来存储变量以及对应的值private Map<Variable,Integer> map = new HashMap<>();//添加变量的功能public void assign(Variable var, Integer value){map.put(var, value);}//根据变量获取对应的值public int getValue(Variable var){return map.get(var);}
}
3.5.测试
Client.java
public class Client {public static void main(String[] args){//创建环境对象Context context = new Context();//创建多个变量对象Variable a = new Variable("a");Variable b = new Variable("b");Variable c = new Variable("c");Variable d = new Variable("d");//将变量存储到环境变量中context.assign(a, 1);context.assign(b, 2);context.assign(c, 3);context.assign(d, 4);//获取抽象语法树 a + b - c + dAbstractExpression expression = new Minus(a, new Plus(new Minus(b, c), d));//解释,即计算int result = expression.interpret(context);System.out.println(expression + "=" + result);}
}
结果如下:
(a-((b-c)+d))=-2
4.优缺点
(1)解释器模式的主要优点是:
- 灵活性:解释器模式可以根据需要动态地修改解释器的表达式,从而扩展或修改语言。
- 易于扩展:新的解释器可以通过扩展抽象语法树节点类来轻松添加到系统中。
- 可重用性:同样的解释器可以在不同的环境下重用,只需要修改解释器的上下文即可。
- 独立性:解释器模式使得解释器与其它部分相互独立,修改解释器不会影响其他部分的功能。
(2)解释器模式的主要缺点是:
- 复杂性:因为解释器模式涉及到抽象语法树、终结符和非终结符等概念,因此实现起来比较复杂。
- 效率问题:由于解释器模式使用递归调用的方式进行解释处理,因此对于复杂的语法和大量的数据处理,可能会导致效率问题。
5.使用场景
(1)解释器模式适用于以下场景:
- 当有一个简单的语法规则,并且需要频繁地对该语法进行解释和执行时,可以考虑使用解释器模式。
- 当需要将一个语言或规则进行扩展或修改时,解释器模式可以提供灵活的扩展性和易于修改的特性。
- 当语法规则相对稳定,但需要根据不同的上下文进行不同的解释时,可以使用解释器模式。
- 当需要解耦语法规则的解释过程与具体的操作时,解释器模式可以将语法解释与操作分离,从而提高代码的可维护性和可扩展性。
- 当需要构建一个能够解释执行特定领域语言的工具或引擎时,解释器模式是一种常用的设计模式。
(2)总之,解释器模式适用于需要解释和执行简单语法规则、动态扩展语言等场景,可以提供灵活性、可扩展性和可维护性。
相关文章:

Java 设计模式——解释器模式
目录 1.概述2.结构3.案例实现3.1.抽象表达式类3.2.终结表达式3.3.非终结表达式3.4.环境类3.5.测试 4.优缺点5.使用场景 1.概述 (1)如下图,设计一个软件用来进行加减计算。我们第一想法可能就是使用工具类,提供对应的加法和减法的…...
面试经典150题——Day37
文章目录 一、题目二、题解 一、题目 73. Set Matrix Zeroes Given an m x n integer matrix matrix, if an element is 0, set its entire row and column to 0’s. You must do it in place. Example 1: Input: matrix [[1,1,1],[1,0,1],[1,1,1]] Output: [[1,0,1],[0,…...

在 Arduino IDE 2.0 中安装 ESP32 板(Windows、Mac OS X、Linux)
有一个新的 Arduino IDE——Arduino IDE 2.0(测试版)。在本教程中,您将学习如何在 Arduino IDE 2.0 中安装 ESP32 板并将代码上传到板。本教程与 Windows、Mac OS X 和 Linux 操作系统兼容。 据 Arduino 网站称:“ Arduino IDE 2.…...
西门子S7-1200PLC混合通信编程(ModbusTcp和UDP通信)
S7-1200PLC的MODBUS-TCP通信 西门子PLC ModbusTcp通信访问网关后从站(SCL语言轮询状态机)-CSDN博客文章浏览阅读305次。西门子PLC的ModbusTcp通信在专栏已有很多文章介绍,所不同的是每个项目的通信需求都略有不同,今天我们以访问网关后的三个从站数据来举例,给出轮询的推荐…...

Hbase 迁移小结:从实践中总结出的最佳迁移策略
在数据存储和处理领域,HBase作为一种分布式、可扩展的NoSQL数据库,被广泛应用于大规模数据的存储和分析。然而,随着业务需求的变化和技术发展的进步,有时候我们需要将现有的HBase数据迁移到其他环境或存储系统。HBase数据迁移是一…...

键盘win键无法使用,win+r不生效、win键没反应、Windows键失灵解决方案(亲测可以解决)
最近几天发现自己笔记本的win键无法使用,win失灵了,但是外接键盘后则正常:。 这个问题困扰了我一周,我都以为自己的枪神坏了。 寻找了几个解决方法,网上看了好多好多稀里糊涂的办法,都是不管用的,这里给大…...

1. 深度学习——激活函数
机器学习面试题汇总与解析——激活函数 本章讲解知识点 什么是激活函数? 为什么要使用激活函数? 详细讲解激活函数 本专栏适合于Python已经入门的学生或人士,有一定的编程基础。本专栏适合于算法工程师、机器学习、图像处理求职的学生或人…...

chatglm3-6b部署及微调
chatglm3-6b部署及微调 modelscope: https://modelscope.cn/models/ZhipuAI/chatglm3-6b/filesgithub: https://github.com/THUDM/ChatGLM3镜像: ubuntu20.04-cuda11.7.1-py38-torch2.0.1-tf1.15.5-1.8.1v100 16G现存 单卡 安装 软件依赖 # 非必要无需执行 # pip install -…...
Hive 知识点八股文记录 ——(二)优化
函数 UDF:用户定义函数 UDAF:用户定义聚集函数 UDTF:用户定义表生成函数 建表优化 分区建桶 创建表时指定分区字段 PARTITIONED BY (date string)指定分桶字段和数量 CLUSTERED BY (id) INTO 10 BUCKETS插入数据按分区、分桶字段插入 …...

计算机技术专业CSIT883系统分析与项目管理介绍
文章目录 前言一、学科学习成果二、使用步骤三、最低出勤要求四、讲座时间表五、项目管理 前言 本课程介绍了信息系统开发中的技术和技术,以及与管理信息技术项目的任务相关的方法和过程。 它研究了系统分析师、客户和用户在系统开发生命周期中的互补角色。 它涵盖…...
gitlab安装地址
镜像地址: Index of /gitlab-ce/yum/el7/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror wget Index of /gitlab-ce/yum/el7/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror rpm -i gitlab-ce-15.9.1-ce.0.el7.x86_64.rpm 一直提示 &#x…...
Spark处理方法_提取文件名中的时间
需求描述 通过读取目录下的类似文件的datapath路径的文件名及文件内容,需要将读取的每一个文件的文件名日期解析出来,并作为读取当前文件内容递归读取当前文件一个df列,列名为“时间”;后面就是读一个文件,解析一下时间…...

技术分享 | 测试平台开发-前端开发之数据展示与分析
测试平台的数据展示与分析,我们主要使用开源工具ECharts来进行数据的展示与分析。 ECharts简介与安装 ECharts是一款基于JavaScript的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表ÿ…...

NZ系列工具NZ06:VBA创建PDF文件说明
我的教程一共九套及VBA汉英手册一部,分为初级、中级、高级三大部分。是对VBA的系统讲解,从简单的入门,到数据库,到字典,到高级的网抓及类的应用。大家在学习的过程中可能会存在困惑,这么多知识点该如何组织…...
redis-cli 连接 sentinel架构的redis服务
之前一直用gui连接redis,今天在服务器连接发现redis-cli无法直接连接到redis-sentinel服务器,研究后发现多了几个步骤,如下: 假设有三个redis节点127.0.0.1,127.0.0.2,127.0.0.3,端口为9696先连接任意一个节点: redis-cli -h 12…...

使用github copilot
现在的大模型的应用太广了,作为程序员我们当然野可以借助大模型来帮我们敲代码。 下面是自己注册使用github copilot的过程。 一、注册github copilot 1. 需要拥有github账号 ,登录github之后,点右侧自己的头像位置,下面会出现…...
1438 绝对差不超过限制的最长连续子数组(单调队列)
题目 绝对差不超过限制的最长连续子数组 给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit 。 如果不存在满足条件的子数组,则返…...
OpenCV入门9:图像增强和图像滤波
图像增强是一种通过对图像进行处理以改善其质量、对比度、清晰度等方面的技术。在OpenCV中,有多种图像增强的方法和函数可用。下面简要介绍一些常见的图像增强方法及其在OpenCV中的实现方式。 直方图均衡化(Histogram Equalization)ÿ…...

Pycharm常用快捷键和替换正则表达式
原生快捷键的使用: 1.CtrlF:查找 2.CtrlZ:返回上一步 3.Alt 鼠标左键选择:多行同时编辑(上、下、左、右键能够移动光标) 按住Ctrl,左键点击,定位光标 编辑过程 URL常用的替换正则表达式&am…...

C#,数值计算——函数计算,Epsalg的计算方法与源程序
1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// Convergence acceleration of a sequence by the algorithm.Initialize by /// calling the constructor with arguments nmax, an upper bound on the /// number of term…...

SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...

【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
Python学习(8) ----- Python的类与对象
Python 中的类(Class)与对象(Object)是面向对象编程(OOP)的核心。我们可以通过“类是模板,对象是实例”来理解它们的关系。 🧱 一句话理解: 类就像“图纸”,对…...