当前位置: 首页 > news >正文

Go和Java实现解释器模式

Go和Java实现解释器模式

下面通过一个四则运算来说明解释器模式的使用。

1、解释器模式

解释器模式提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口

解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。

  • 意图:给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。

  • 主要解决:对于一些固定文法构建一个解释句子的解释器。

  • 何时使用:如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单

    语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。

  • 如何解决:构建语法树,定义终结符与非终结符。

  • 关键代码:构建环境类,包含解释器之外的一些全局信息,一般是 HashMap。

  • 应用实例:编译器、运算表达式计算。

  • 优点:1、可扩展性比较好,灵活。 2、增加了新的解释表达式的方式。 3、易于实现简单文法。

  • 缺点:1、可利用场景比较少。 2、对于复杂的文法比较难维护。 3、解释器模式会引起类膨胀。 4、解释器模

    式采用递归调用方法。

  • 使用场景:1、可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。 2、一些重复出现的问题可

    以用一种简单的语言来进行表达。 3、一个简单语法需要解释的场景。

  • 注意事项:可利用场景比较少,JAVA 中如果碰到可以用 expression4J 代替。

  • 适用性:

    当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式,而当

    存在当下情况时该模式效果最好:

    该文法简单对于复杂的文法,文法的层次变得庞大而无法管理。

    效率不是一个关键问题最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将它们转换成另

    一种形式。

2、Go实现解释器模式

package interpreter// ========== ArithmeticInterpreter ==========
type ArithmeticInterpreter interface {Interpret() int
}
package interpreter// ========== NumInterpreter ==========
type NumInterpreter struct {Value int
}func NewNumInterpreter(value int) *NumInterpreter {return &NumInterpreter{Value: value}
}func (numInterpreter *NumInterpreter) Interpret() int {return numInterpreter.Value
}
package interpreter// ========== AddInterpreter ==========
type AddInterpreter struct {left  ArithmeticInterpreterright ArithmeticInterpreter
}func NewAddInterpreter(left, right ArithmeticInterpreter) *AddInterpreter {return &AddInterpreter{left: left, right: right}
}func (addInterpreter *AddInterpreter) Interpret() int {return addInterpreter.left.Interpret() + addInterpreter.right.Interpret()
}
package interpreter// ========== SubInterpreter ==========
type SubInterpreter struct {left  ArithmeticInterpreterright ArithmeticInterpreter
}func NewSubInterpreter(left, right ArithmeticInterpreter) *SubInterpreter {return &SubInterpreter{left: left, right: right}
}func (subInterpreter *SubInterpreter) Interpret() int {return subInterpreter.left.Interpret() - subInterpreter.right.Interpret()
}
package interpreter// ========== MultiInterpreter ==========
type MultiInterpreter struct {left  ArithmeticInterpreterright ArithmeticInterpreter
}func NewMultiInterpreter(left, right ArithmeticInterpreter) *MultiInterpreter {return &MultiInterpreter{left: left, right: right}
}func (multiInterpreter *MultiInterpreter) Interpret() int {return multiInterpreter.left.Interpret() * multiInterpreter.right.Interpret()
}
package interpreter// ========== DivInterpreter ==========
type DivInterpreter struct {left  ArithmeticInterpreterright ArithmeticInterpreter
}func NewDivInterpreter(left, right ArithmeticInterpreter) *DivInterpreter {return &DivInterpreter{left: left, right: right}
}func (divInterpreter *DivInterpreter) Interpret() int {return divInterpreter.left.Interpret() / divInterpreter.right.Interpret()
}
package interpreterconst (ADD = "+"SUB = "-"MUL = "*"DIV = "/"
)// =========== OperatorUtil ==========
type OperatorUtil struct{}func (OperatorUtil *OperatorUtil) IsOperator(symbol string) bool {return ("+" == symbol || "-" == symbol || "*" == symbol)
}func (operatorUtil *OperatorUtil) GetInterpreter(left, right ArithmeticInterpreter, symbol string) ArithmeticInterpreter {if ADD == symbol {return NewAddInterpreter(left, right)} else if SUB == symbol {return NewSubInterpreter(left, right)} else if MUL == symbol {return NewMultiInterpreter(left, right)} else if DIV == symbol {return NewDivInterpreter(left, right)}return nil
}
package interpreterimport ("fmt""strconv""strings"
)type Calculator struct{}var (operatorUtil = OperatorUtil{}stack        = make([]ArithmeticInterpreter, 0)
)func (calculator *Calculator) Parse(expression string) {elements := strings.Split(expression, " ")var leftExpr, rightExpr ArithmeticInterpreterfor i := 0; i < len(elements); i++ {operator := elements[i]if operatorUtil.IsOperator(operator) {// 出栈leftExpr = stack[len(stack)-1]stack = stack[:len(stack)-1]i++ele, _ := strconv.Atoi(elements[i])rightExpr = NewNumInterpreter(ele)fmt.Printf("出栈: %d 和 %d \n", leftExpr.Interpret(), rightExpr.Interpret())stack = append(stack, operatorUtil.GetInterpreter(leftExpr, rightExpr, operator))fmt.Println("应用运算符: " + operator)} else {ele, _ := strconv.Atoi(elements[i])numInterpreter := NewNumInterpreter(ele)stack = append(stack, numInterpreter)fmt.Printf("入栈: %d \n", numInterpreter.Interpret())}}}func (calculator *Calculator) Result() int {value := stack[len(stack)-1]stack = stack[:len(stack)-1]return value.Interpret()
}
package mainimport ("fmt". "proj/interpreter"
)func main() {calculator := Calculator{}calculator.Parse("10 + 30")fmt.Println("result:", calculator.Result())calculator.Parse("10 + 30 - 20")fmt.Println("result: ", calculator.Result())calculator.Parse("100 * 2 + 400 - 20 + 66")fmt.Println("result:", calculator.Result())
}
# 程序输出
入栈: 10 
出栈: 1030   
应用运算符: +
result: 40
入栈: 10 
出栈: 1030 
应用运算符: +
出栈: 4020 
应用运算符: -
result:  20
入栈: 100 
出栈: 1002 
应用运算符: *
出栈: 200400 
应用运算符: +
出栈: 60020 
应用运算符: -
出栈: 58066 
应用运算符: +
result: 40
入栈: 10 
出栈: 1030 
应用运算符: +
出栈: 4020 
应用运算符: -
result:  20
入栈: 100 
出栈: 1002 
应用运算符: *
出栈: 200400 
应用运算符: +
出栈: 60020 
应用运算符: -
出栈: 58066 
应用运算符: +
result: 646

3、Java实现解释器模式

package com.interpreter;// ========== ArithmeticInterpreter ==========
public interface ArithmeticInterpreter {int interpret();
}
package com.interpreter;// ========== ArithmeticInterpreter ==========
public abstract class Interpreter implements ArithmeticInterpreter{protected ArithmeticInterpreter left;protected ArithmeticInterpreter right;public Interpreter(ArithmeticInterpreter left, ArithmeticInterpreter right) {this.left = left;this.right = right;}
}
package com.interpreter;// ========== NumInterpreter ==========
public class NumInterpreter implements ArithmeticInterpreter {private int value;public NumInterpreter(int value) {this.value = value;}@Overridepublic int interpret() {return this.value;}}
package com.interpreter;// ========== AddInterpreter ==========
public class AddInterpreter extends Interpreter {public AddInterpreter() {super(left, right);}@Overridepublic int interpret() {return this.left.interpret() + this.right.interpret();}
}
package com.interpreter;// ========== MultiInterpreter ==========
public class MultiInterpreter extends Interpreter {public MultiInterpreter(ArithmeticInterpreter left, ArithmeticInterpreter right) {super(left, right);}@Overridepublic int interpret() {return this.left.interpret() * this.right.interpret();}
}
package com.interpreter;// ========== SubInterpreter ==========
public class SubInterpreter  extends Interpreter {public SubInterpreter(ArithmeticInterpreter left, ArithmeticInterpreter right) {super(left, right);}@Overridepublic int interpret() {return this.left.interpret() - this.right.interpret();}
}
package com.interpreter;// ========== DivInterpreter ==========
public class DivInterpreter extends Interpreter {public DivInterpreter(ArithmeticInterpreter left, ArithmeticInterpreter right) {super(left, right);}@Overridepublic int interpret() {return this.left.interpret() / this.right.interpret();}
}
package com.interpreter;// =========== OperatorUtil ==========
public class OperatorUtil {private final static String ADD = "+";private final static String SUB = "-";private final static String MUL = "*";private final static String DIV = "/";public static boolean isOperator(String symbol) {return ("+".equals(symbol) || "-".equals(symbol) || "*".equals(symbol));}public static Interpreter getInterpreter(ArithmeticInterpreter left, ArithmeticInterpreter right, String symbol) {if (ADD.equals(symbol)) {return new AddInterpreter(left, right);} else if (SUB.equals(symbol)) {return new SubInterpreter(left, right);} else if (MUL.equals(symbol)) {return new MultiInterpreter(left, right);} else if (DIV.equals(symbol)) {return new DivInterpreter(left, right);}return null;}
}
package com.interpreter;import java.util.Stack;// ========== Calculator ==========
public class Calculator {private final Stack<ArithmeticInterpreter> stack = new Stack<>();public void parse(String expression) {String[] elements = expression.split(" ");ArithmeticInterpreter leftExpr, rightExpr;for (int i = 0; i < elements.length; i++) {String operator = elements[i];if (OperatorUtil.isOperator(operator)) {leftExpr = this.stack.pop();rightExpr = new NumInterpreter(Integer.parseInt(elements[++i]));System.out.println("出栈: " + leftExpr.interpret() + " 和 " + rightExpr.interpret());this.stack.push(OperatorUtil.getInterpreter(leftExpr, rightExpr, operator));System.out.println("应用运算符: " + operator);} else {NumInterpreter numInterpreter = new NumInterpreter(Integer.parseInt(elements[i]));this.stack.push(numInterpreter);System.out.println("入栈: " + numInterpreter.interpret());}}}public int result() {return this.stack.pop().interpret();}}
package com.interpreter;public class Test {public static void main(String[] args) {Calculator calculator = new Calculator();calculator.parse("10 + 30");System.out.println("result: " + calculator.result());calculator.parse("10 + 30 - 20");System.out.println("result: " + calculator.result());calculator.parse("100 * 2 + 400 - 20 + 66");System.out.println("result: " + calculator.result());}
}
# 程序输出
入栈: 10
出栈: 1030
应用运算符: +
result: 40
入栈: 10
出栈: 1030
应用运算符: +
出栈: 4020
应用运算符: -
result: 20
入栈: 100
出栈: 1002
应用运算符: *
出栈: 200400
应用运算符: +
出栈: 60020
应用运算符: -
出栈: 58066
应用运算符: +
result: 646

相关文章:

Go和Java实现解释器模式

Go和Java实现解释器模式 下面通过一个四则运算来说明解释器模式的使用。 1、解释器模式 解释器模式提供了评估语言的语法或表达式的方式&#xff0c;它属于行为型模式。这种模式实现了一个表达式接口&#xff0c;该接口 解释一个特定的上下文。这种模式被用在 SQL 解析、符…...

域名配置HTTPS

一、注册域名 这个可以在各大平台注册&#xff0c;具体看一下就会注册了&#xff0c;自己挑选一个自己喜欢的域名。 步骤一般也就是先实名&#xff0c;实名成功了才能注册域名。 二、办理SSL证书 这里使用的是阿里云的SSL免费证书 1、申请证书 二、填写申请 三、域名绑定生…...

机械设计cad,ug编程设计,ug模具设计,SolidWorks模具设计

模具设计培训课程&#xff1a; 【第一阶段&#xff1a;CAD识图制图】 [AutoCAD机械制图]&#xff1a;全面讲解AUTOCAD应用知识&#xff0c;常用命令讲解与运用&#xff0c;二维平面图绘制&#xff0c;三维成型零件的绘制与设计&#xff0c;制作工程图 【第二阶段&#xff1a;U…...

嵌入式开发的学习与未来展望:借助STM32 HAL库开创创新之路

引言&#xff1a; 嵌入式开发作为计算机科学领域的重要分支&#xff0c;为我们的日常生活和产业发展提供了无限的可能。STMicroelectronics的STM32系列芯片以其出色的性能和广泛的应用领域而备受关注。而STM32 HAL库作为嵌入式开发的高级库&#xff0c;为学习者提供了更高效、更…...

WPS-0DAY-20230809的分析和利用复现

WPS-0DAY-20230809的分析和初步复现 一、漏洞学习1、本地复现环境过程 2、代码解析1.htmlexp.py 3、通过修改shellcode拿shell曲折的学习msf生成sc 二、疑点1、问题2、我的测试测试方法测试结果 一、漏洞学习 强调&#xff1a;以下内容仅供学习和测试&#xff0c;一切行为均在…...

MongoDB(三十九)

目录 一、概述 &#xff08;一&#xff09;相关概念 &#xff08;二&#xff09;特性 二、应用场景 三、安装 &#xff08;一&#xff09;编译安装 &#xff08;二&#xff09;yum安装 1、首先制作repo源 2、软件包名&#xff1a;mongodb-org 3、启动服务&#xff1a…...

InnoDB引擎

1 逻辑存储结构 InnoDB的逻辑存储结构如下图所示: 1). 表空间 表空间是InnoDB存储引擎逻辑结构的最高层&#xff0c; 如果用户启用了参数 innodb_file_per_table(在8.0版本中默认开启) &#xff0c;则每张表都会有一个表空间&#xff08;xxx.ibd&#xff09;&#xff0c;一个…...

CSS3中的var()函数

目录 定义&#xff1a; 语法&#xff1a; 用法&#xff1a; 定义&#xff1a; var()函数是一个 CSS 函数用于插入自定义属性&#xff08;有时也被称为“CSS 变量”&#xff09;的值 语法&#xff1a; var(custom-property-name, value) 函数的第一个参数是要替换的自定义属性…...

opencv图片换背景色

#include <iostream> #include<opencv2/opencv.hpp> //引入头文件using namespace cv; //命名空间 using namespace std;//opencv这个机器视觉库&#xff0c;它提供了很多功能&#xff0c;都是以函数的形式提供给我们 //我们只需要会调用函数即可in…...

JAVA语言:什么是懒加载机制?

JVM没有规定什么时候加载,一般是什么时候使用这个class才会什么时候加载,但是JVM规定了什么时候必须初始化(初始化是第三步、装载、连接、初始化),只要加载之后,那么肯定是要进行初始化的,所以我们就可以通过查看这个类有没有进行初始化,从而判断这个类有没有被加载。 …...

jupyter默认工作目录的更改

1、生成配置文件&#xff1a;打开Anaconda Prompt&#xff0c;输入如下命令 jupyter notebook --generate-config询问[y/N]时输入y 2、配置文件修改&#xff1a;根据打印路径打开配置文件jupyter_notebook_config.py&#xff0c;全文搜索找到notebook_dir所在位置。在单引号中…...

Flutter系列文章-Flutter UI进阶

在本篇文章中&#xff0c;我们将深入学习 Flutter UI 的进阶技巧&#xff0c;涵盖了布局原理、动画实现、自定义绘图和效果、以及 Material 和 Cupertino 组件库的使用。通过实例演示&#xff0c;你将更加了解如何创建复杂、令人印象深刻的用户界面。 第一部分&#xff1a;深入…...

Elasticsearch在部署时,对Linux的设置有哪些优化方法?

部署Elasticsearch时&#xff0c;可以通过优化Linux系统的设置来提升性能和稳定性。以下是一些常见的优化方法&#xff1a; 1.文件描述符限制 Elasticsearch需要大量的文件描述符来处理数据和连接&#xff0c;所以确保调整系统的文件描述符限制。可以通过修改 /etc/security/…...

【网络基础】应用层协议

【网络基础】应用层协议 文章目录 【网络基础】应用层协议1、协议作用1.1 应用层需求1.2 协议分类 2、HTTP & HTTPS2.1 HTTP/HTTPS 简介2.2 HTTP工作原理2.3 HTTPS工作原理2.4 区别 3、URL3.1 编码解码3.2 URI & URL 4、HTTP 消息结构4.1 HTTP请求方法4.2 HTTP请求头信…...

面试八股文Mysql:(1)事务实现的原理

1. 什么是事务 事务就是一组数据库操作&#xff0c;这些操作是一个atomic&#xff08;原子性的操作&#xff09; &#xff0c;不可分割&#xff0c;要么都执行&#xff0c;要么回滚&#xff08;rollback&#xff09;都不执行。这样就避免了某个操作成功某个操作失败&#xff0…...

Linux学习之sed多行模式

N将下一行加入到模式空间 D删除模式空间中的第一个字符到第一个换行符 P打印模式空间中的第一个字符到第一个换行符 doubleSpace.txt里边的内容如下&#xff1a; goo d man使用下边的命令可以实现把上边对应的内容放到doubleSpace.txt。 echo goo >> doubleSpace.txt e…...

【刷题笔记8.15】【链表相关】LeetCode:合并两个有序链表、反转链表

LeetCode&#xff1a;【链表相关】合并两个有序链表 题目1&#xff1a;合并两个有序链表 题目描述 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3…...

神经网络基础-神经网络补充概念-11-向量化逻辑回归

概念 通过使用 NumPy 数组来进行矩阵运算&#xff0c;将循环操作向量化。 向量化的好处在于它可以同时处理多个样本&#xff0c;从而加速计算过程。在实际应用中&#xff0c;尤其是处理大规模数据集时&#xff0c;向量化可以显著提高代码的效率。 代码实现-以逻辑回归为例 i…...

openGauss学习笔记-40 openGauss 高级数据管理-锁

文章目录 openGauss学习笔记-40 openGauss 高级数据管理-锁40.1 语法格式40.2 参数说明40.3 示例 openGauss学习笔记-40 openGauss 高级数据管理-锁 如果需要保持数据库数据的一致性&#xff0c;可以使用LOCK TABLE来阻止其他用户修改表。 例如&#xff0c;一个应用需要保证表…...

勘探开发人工智能技术:机器学习(6)

0 提纲 7.1 循环神经网络RNN 7.2 LSTM 7.3 Transformer 7.4 U-Net 1 循环神经网络RNN 把上一时刻的输出作为下一时刻的输入之一. 1.1 全连接神经网络的缺点 现在的任务是要利用如下语料来给apple打标签&#xff1a; 第一句话&#xff1a;I like eating apple!(我喜欢吃苹…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测

uniapp 中配置 配置manifest 文档&#xff1a;manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号&#xff1a;4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)

引言 工欲善其事&#xff0c;必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后&#xff0c;我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集&#xff0c;就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...