当前位置: 首页 > 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!(我喜欢吃苹…...

大麦网自动抢票神器:5分钟配置,告别抢票焦虑的终极指南

大麦网自动抢票神器&#xff1a;5分钟配置&#xff0c;告别抢票焦虑的终极指南 【免费下载链接】ticket-purchase 大麦自动抢票&#xff0c;支持人员、城市、日期场次、价格选择 项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase 还在为心仪演唱会门票…...

机房动环监控系统是什么?其主要功能及智能运用方向有哪些?

机房动环监控系统的重要性 为信息技术的稳健运行提供了保障&#xff0c;尤其是在现代社会日益依赖数据和信息的背景下。利用实时监测电力、温度、湿度环境参数发生&#xff0c;还大幅度降低了因停机带来的经济损失。以大榕树科技为例&#xff0c;他们采用先进的监控系统&#x…...

技术革新:FModel如何重塑游戏资源逆向工程与创作流程

技术革新&#xff1a;FModel如何重塑游戏资源逆向工程与创作流程 【免费下载链接】FModel Unreal Engine Archives Explorer 项目地址: https://gitcode.com/gh_mirrors/fm/FModel 在游戏开发与内容创作的生态系统中&#xff0c;资源逆向工程长期以来都是一项技术壁垒高…...

ComfyUI-Impact-Pack V8:AI图像细节增强的终极指南

ComfyUI-Impact-Pack V8&#xff1a;AI图像细节增强的终极指南 【免费下载链接】ComfyUI-Impact-Pack Custom nodes pack for ComfyUI This custom node helps to conveniently enhance images through Detector, Detailer, Upscaler, Pipe, and more. 项目地址: https://git…...

【2026年世界模型最全综述】:从开山之作到Sora与Genie 3

论文信息 标题&#xff1a;Understanding World or Predicting Future? A Comprehensive Surveyof World Models会议&#xff1a;ACM Computing Surveys 2026&#xff08;计算机领域顶级综述期刊&#xff09;单位&#xff1a;清华大学FIB-Lab代码&#xff1a;https://github.c…...

用STM32F401和千分之一精度电阻,我亲手焊了个10位R-2R DAC,误差竟然小于1.5mV

从零打造10位R-2R DAC&#xff1a;高精度电阻与STM32的实战碰撞 在电子设计领域&#xff0c;数模转换器&#xff08;DAC&#xff09;是实现数字信号到模拟信号转换的核心部件。而R-2R梯形电阻网络因其结构简单、成本低廉的特点&#xff0c;成为DIY爱好者实现DAC功能的热门选择。…...

【VMware虚拟机】Linux下ubuntu连接网络详细讲解!

原理讲解 window上网需要网络适配器&#xff0c;通过家用路由器下发WLAN&#xff0c;自分配ip地址&#xff0c;连接即用 linux同理&#xff1a;在VMware虚拟机上需要”虚拟路由器“。对应为虚拟网络编辑器 1.打开虚拟网络编辑器 2.点击NAT&#xff0c;NAT模式和DHCP必须选上…...

2025睿抗机器人大赛智能侦查赛道省赛全流程——基础了解

2025睿抗机器人大赛智能侦查赛道省赛全流程——基础了解 智能侦查赛道概述 2025 睿抗机器人大赛智能侦察赛道是 CAIR 工程竞技赛道下的专业国防装备赛项&#xff0c;以无人侦察车为载体、模拟巷战环境开展军事侦察任务&#xff0c;核心培养学生国防意识与科技创新能力且核心硬件…...

安科士(AndXe)SPF-10G-T :10G 电口模块,重塑短距网络升级性价比

数字化转型浪潮下&#xff0c;企业园区、数据中心对10Gbps 高速互联的需求呈爆发式增长。但传统 10G 升级方案深陷困境&#xff1a;光纤布线成本高昂、施工周期长且需专业运维技能&#xff0c;而多数企业机架内、相邻机架间及办公楼层内的链路距离普遍低于 30 米&#xff0c;光…...

深入Linux内核:图解PTP硬件时间戳(HW Timestamp)从网卡到用户空间的完整路径

深入Linux内核&#xff1a;图解PTP硬件时间戳从网卡到用户空间的完整路径 1. 高精度时间同步的技术演进与PTP核心价值 在分布式系统与工业自动化领域&#xff0c;微秒级甚至纳秒级的时间同步已成为刚需。传统NTP协议受限于软件实现和网络抖动&#xff0c;精度通常只能达到毫秒级…...