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

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准

城市路内停车管理常因行道树遮挡、高位设备盲区等问题&#xff0c;导致车牌识别率低、逃费率高&#xff0c;传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法&#xff0c;正成为破局关键。该设备安装于车位侧方0.5-0.7米高度&#xff0c;直接规避树枝遮…...

MySQL 主从同步异常处理

阅读原文&#xff1a;https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主&#xff0c;遇到的这个错误&#xff1a; Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一&#xff0c;通常表示&#xff…...

【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权

摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题&#xff1a;安全。文章将详细阐述认证&#xff08;Authentication) 与授权&#xff08;Authorization的核心概念&#xff0c;对比传统 Session-Cookie 与现代 JWT&#xff08;JS…...

基于Python的气象数据分析及可视化研究

目录 一.&#x1f981;前言二.&#x1f981;开源代码与组件使用情况说明三.&#x1f981;核心功能1. ✅算法设计2. ✅PyEcharts库3. ✅Flask框架4. ✅爬虫5. ✅部署项目 四.&#x1f981;演示效果1. 管理员模块1.1 用户管理 2. 用户模块2.1 登录系统2.2 查看实时数据2.3 查看天…...

Spring事务传播机制有哪些?

导语&#xff1a; Spring事务传播机制是后端面试中的必考知识点&#xff0c;特别容易出现在“项目细节挖掘”阶段。面试官通过它来判断你是否真正理解事务控制的本质与异常传播机制。本文将从实战与源码角度出发&#xff0c;全面剖析Spring事务传播机制&#xff0c;帮助你答得有…...