口译员设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。

在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因,并了解何时以及如何应用模式中的每一个。 在这里查看 !

目录

1.简介 2.什么是口译员设计模式 3.实施口译员设计模式 4.何时使用口译员设计模式 5. JDK中的解释器设计模式 6.下载源代码

1.简介

口译员设计模式是一种重型模式。 这一切都是关于通过创建针对自己的编程语言的解释器来组合自己的编程语言,或处理现有的编程语言。 要使用这种模式,您必须对正规语法有一定的了解,才能将一种语言组合在一起。 可以想象,这是开发人员每天都不会真正使用的模式之一,因为创建自己的语言并不是很多人要做的事情。

例如,就形式语法而言,以新语言定义表达式可能类似于以下代码片段:

expression ::= <command> | <repetition> | <sequence>

那么,使用新语言的每个表达式可能由命令,命令的重复和序列表达式组成。 每个项目都可以使用解释方法表示为一个对象,以将您的新语言翻译成可以在Java中运行的语言。

为了说明解释器设计模式的用法,我们创建一个示例来解决简单的数学表达式,但在此之前,让我们在下面的部分中讨论有关解释器设计模式的一些详细信息。

2.什么是口译员设计模式

给定一种语言,请定义其语法的表示形式,以及使用该表示形式来解释该语言句子的解释器。

通常,语言由一组语法规则组成。 遵循这些语法规则可以构建不同的句子。 有时应用程序可能需要处理重复出现的相似请求,这些请求是一组语法规则的组合。 这些请求是不同的,但从某种意义上来说它们是相似的,因为它们都是使用同一组规则构成的。

一个简单的例子就是提交给计算器程序的一组不同的算术表达式。 尽管每个这样的表达式都不同,但是它们都是使用构成算术表达式语言语法的基本规则构造的。

在这种情况下,代替将每个不同的规则组合视为一个单独的案例,对应用程序来说,具有解释规则的通用组合的能力可能是有益的。 解释器模式可用于在应用程序中设计此功能,以便其他应用程序和用户可以使用由一组语法规则定义的简单语言来指定操作。

可以将类层次结构设计为表示语法规则集,而层次结构中的每个类都表示一个单独的语法规则。 可以将解释器模块设计为解释使用上面设计的类层次结构构造的句子,并执行必要的操作。

由于每个语法规则都代表一个不同的类别,因此类别的数量会随着语法规则的数量而增加。 具有广泛而复杂的语法规则的语言需要大量的类。 语法简单时,解释器模式最有效。 具有简单的语法避免了需要具有许多与所涉及的复杂规则集相对应的类,而这些类很难管理和维护。

图1-类图

图1-类图

抽象表达

  • 声明抽象语法树中所有节点共有的抽象Interpret操作。

终端表达

  • 实现与语法中的终端符号关联的Interpret操作。
  • 句子中每个终端符号都需要一个实例。

非末端表达

  • 语法中的每个规则R ::= R1 R2 ... Rn都需要一个这样的类。
  • 为每个符号R1Rn维护类型AbstractExpression实例变量。
  • 为语法中的非终结符实现Interpret操作。 Interpret通常对表示R1Rn的变量进行递归调用。

语境

  • 包含解释器的全局信息。

客户

  • 构建(或给定)抽象语法树,该语法树以语法定义的语言表示特定的句子。 抽象语法树是根据NonterminalExpressionTerminalExpression类的实例组装而成的。
  • 调用Interpret操作。

3.实施口译员设计模式

package com.javacodegeeks.patterns.interpreterpattern;public interface Expression {public int interpret();
}

所有不同的具体表达式都使用上面的接口,并且覆盖了解释方法以定义它们在表达式上的特定操作。

以下是特定于操作的表达式类。

package com.javacodegeeks.patterns.interpreterpattern;public class Add implements Expression{private final Expression leftExpression;private final Expression rightExpression;public Add(Expression leftExpression,Expression rightExpression ){this.leftExpression = leftExpression;this.rightExpression = rightExpression;}@Overridepublic int interpret() {return leftExpression.interpret() + rightExpression.interpret();}}
package com.javacodegeeks.patterns.interpreterpattern;public class Product implements Expression{private final Expression leftExpression;private final Expression rightExpression;public Product(Expression leftExpression,Expression rightExpression ){this.leftExpression = leftExpression;this.rightExpression = rightExpression;}@Overridepublic int interpret() {return leftExpression.interpret() * rightExpression.interpret();}
}
package com.javacodegeeks.patterns.interpreterpattern;public class Substract implements Expression{private final Expression leftExpression;private final Expression rightExpression;public Substract(Expression leftExpression,Expression rightExpression ){this.leftExpression = leftExpression;this.rightExpression = rightExpression;}@Overridepublic int interpret() {return leftExpression.interpret() - rightExpression.interpret();}}
package com.javacodegeeks.patterns.interpreterpattern;public class Number implements Expression{private final int n;public Number(int n){this.n = n;}@Overridepublic int interpret() {return n;}}

下面是可选的实用程序类,其中包含用于执行表达式的不同实用程序方法。

package com.javacodegeeks.patterns.interpreterpattern;public class ExpressionUtils {public static boolean isOperator(String s) {if (s.equals("+") || s.equals("-") || s.equals("*"))return true;elsereturn false;}public static Expression getOperator(String s, Expression left,	Expression right) {switch (s) {case "+":return new Add(left, right);case "-":return new Substract(left, right);case "*":return new Product(left, right);}return null;}}

现在,让我们测试示例。

package com.javacodegeeks.patterns.interpreterpattern;import java.util.Stack;public class TestInterpreterPattern {public static void main(String[] args) {String tokenString = "7 3 - 2 1 + *";Stack<Expression> stack = new Stack<>();String[] tokenArray = tokenString.split(" ");for (String s : tokenArray) {if (ExpressionUtils.isOperator(s)) {Expression rightExpression = stack.pop();Expression leftExpression = stack.pop();Expression operator = ExpressionUtils.getOperator(s, leftExpression,rightExpression);int result = operator.interpret();stack.push(new Number(result));} else {Expression i = new Number(Integer.parseInt(s));stack.push(i);}}System.out.println("( "+tokenString+" ): "+stack.pop().interpret());}}

上面的代码将提供以下输出:

( 7 3 - 2 1 + * ): 12

请注意,我们已使用后缀表达式来解决它。

如果您不了解后缀,则这里有一个简短的介绍。 数学表达式有三种表示法,即中缀,后缀和前缀。

  • 前缀表示法是常用的算术和逻辑公式表示法,其中运算符在它们所作用的操作数之间(例如3+4以infix样式编写。
  • 后缀也称为反向波兰表示法(RPN)是一种数学表示法,其中每个运算符都遵循其所有操作数,例如34+
  • 前缀 (波兰表示法)是一种用于逻辑,算术和代数的表示法,其中运算符位于其操作数的左侧,例如+34

Infix表示法通常在数学表达式中使用。 编程语言的解释程序将其他两个符号用作数学表达式的语法。

在上面的类中,我们在tokenString变量中声明了表达式的后缀。 然后,我们拆分tokenString并将其分配到一个数组tokenArray 。 在逐个迭代令牌时,首先我们检查了令牌是运算符还是操作数。 如果令牌是操作数,则将其推入堆栈,但如果是运算符,则从堆栈中弹出前两个操作数。 ExpressionUtilsgetOperation方法根据传递给它的运算符返回适当的表达式类。

然后,我们解释结果并将其推回堆栈。 迭代完整的tokenList我们得到了最终结果。

4.何时使用口译员设计模式

有一种要解释的语言时,请使用解释器模式,并且可以将语言中的语句表示为抽象语法树。 解释器模式在以下情况下效果最佳

  • 语法很简单。 对于复杂的语法,语法的类层次结构会变得庞大且难以管理。 在这种情况下,解析器生成器之类的工具是更好的选择。 他们可以在不构建抽象语法树的情况下解释表达式,这可以节省空间并可能节省时间。
  • 效率不是关键问题。 通常,最有效的解释器不是通过直接解释解析树来实现的,而是先将其转换为另一种形式。 例如,正则表达式通常被转换为状态机。 但是即使那样,翻译器也可以通过Interpreter模式实现,因此该模式仍然适用。

5. JDK中的解释器设计模式

  • java.util.Pattern
  • java.text.Normalizer
  • java.text.Format

6.下载源代码

这是关于口译员设计模式的课程。 您可以在此处下载源代码: InterpreterPattern-Project

翻译自: https://www.javacodegeeks.com/2015/09/interpreter-design-pattern.html

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

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

相关文章

weblogic 升级bsu_Weblogic补丁升级之坑坑洼洼

[概述]虽然当前国内去IOE波涛汹涌&#xff0c;但不可否认OracleWeblogic当前市场还有有一定使用量。所以&#xff0c;weblogic依然是中间件运维的重要工作之一。然而Oracleweblogic已经连续三个季度(2019年10月~2020年7月)曝出CVSS风险为9.8的高危安全漏洞&#xff0c;漏洞修复…

「Unity」UGUI的Text实现首行缩进的办法

我的Unity版本&#xff1a;5.3.5f1 直接说正事 Unity的Text组件&#xff0c;想实现代码拿到一段话&#xff0c;在前面加个缩进&#xff0c;让之后的字符依次后移。 有人觉得很简单&#xff0c;然后就这样写了&#xff1a; 但是尝试过的人就会发现&#xff0c;如果用代码在最前…

【TypeScript系列教程11】函数的使用

目录 TypeScript 函数 函数定义 实例 实例 函数返回值 实例 带参数函数 实例 JavaScript

uniapptabbar的高度是多少_【报Bug】uniapp页面底部空出了tabBar的高度

首页设置隐藏tabBarcodeindex.vueonShow() {uni.hideTabBar({success: (res) > {console.log(hideTabBar-success,res)},fail: (err) > {console.log(hideTabBar-fail,err)}});},onHide() {uni.showTabBar({success: (res) > {console.log(showTabBar-success,res)},f…

在Eclipse中配置Tomcat7.0

为了在Eclipse中进行struts2的测试,才发现自己机器上的Eclipse没有集成Tomcat,在网上找了半天&#xff0c;不是这个插件没有下载地址&#xff0c;就是那个有好多注意事项或者版本问题。结果&#xff0c;自己到tomcatforEclipse的插件的网上直接下载了一个&#xff0c;按照提供的…

【TypeScript系列教程12】Number对象的基本使用

目录 TypeScript Number 语法 Number 对象属性 JavaScript NaN 实例 prototype 实例 Number 对象方法 TypeScript Number TypeScript 与 JavaScript 类似,支持 Number 对象。 Number 对象是原始数值的包装对象。

新建maven写页面_使用 IDEA 创建 Maven Web 项目 (三)- 编写一个简单的 WEB 应用

编写 Servlet 类首先&#xff0c;需要在 java 目录下&#xff0c;创建一个名为 org.smart4j.chapter1 的包。然后&#xff0c;在该包下创建一个 HelloServlet 的类&#xff0c;代码如下&#xff1a;package org.smart4j.chapter1;import javax.servlet.ServletException;impor…

Datepicker

本文翻译自官网&#xff1a; https://angular-ui.github.io/bootstrap 目录&#xff1a; 1. DatePicker 2. DatePicker popup 一、DatePicker https://angular-ui.github.io/bootstrap/#/datepicker 1. 三种模式 Datepicker是灵活&#xff0c;完全可定制的。它有3种模式&#…

cobertura 使用_使用Cobertura,JUnit,HSQLDB,JPA涵盖您的测试

cobertura 使用你好&#xff01;你好吗&#xff1f; 今天让我们谈谈一个非常有用的工具&#xff0c;名为“ Cobertura”。 该框架与我们在另一篇文章中看到的Emma框架具有相同的功能。 Cobertura和Emma之间的主要区别在于Cobertura显示带有图形的简历页面。 如果要查看有关此…

【TypeScript系列教程13】String 字符串对象的基本使用

目录 TypeScript String(字符串) 语法 String 对象属性 弦方法 TypeScript String(字符串) String 对象用于处理文本(字符串)。 语法 var txt = new String("string"); 或者更简单方式: var txt = "string";String 对象属性 下表列出了 Stri…

Matlab和C++混合编程

1 利用 mexopencv 实现各种数据的转换 int i MxArray(prhs[0]).toInt(); double d MxArray(prhs[0]).toDouble(); bool b MxArray(prhs[0]).toBool(); std::string s MxArray(prhs[0]).toString(); cv::Mat mat MxArray(prhs[0]).toMat(); // For pixels cv::Mat ndmat M…

摇杆控制方向原理_图文全面讲解多种方向控制阀的原理和区别....

液压阀是用来控制液压系统中油液的流动方向或调节其流量和压力的。方向控制阀作为液压阀的一种&#xff0c;利用流道的更换控制着油液的流动方向单向型方向控制阀是只允许气流沿一个方向流动的方向控制阀&#xff0c;如单向阀、梭阀、双压阀等换向型方向控制阀是可以改变气流流…

原型设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。 在本课程中&#xff0c;您将深入研究大量的设计模式&#xff0c;并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因&#xff0c;并了解何时以及如何应用模式中的每一个。 在这里查看 &#xff01; 目录 …

【TypeScript系列教程14】Array数组对象的常见的方法

目录 TypeScript Array(数组) concat() every() filter() forEach() join() lastIndexOf() map() pop() push(

DELPHI跨平台的临界替代者

在WINDOWS里面使用临界来保护多线程需要访问的共享对象&#xff0c;现在&#xff0c;DELPHI有了新的跨平台临界保护者--System.TMonitor 代码演示如下&#xff1a; FConnections : TObjectDictionary<TIdTCPConnection,TDSTCPChannel>.Create; 。。。 procedure TCMServe…

laravel 控制器中使用中间件_在 Laravel 中使用 Slack 进行异常通知

php中文网最新课程每日17点准时技术干货分享异常处理是软件开发过程中无法逃避的问题。对于一套设计良好代码高效的程序&#xff0c;出现异常的可能性会比较低&#xff0c;但这并不意味着不会出现异常,有些异常甚至会引起严重的后果&#xff0c;所以如何及时的发现程序中的异常…

【TypeScript系列教程15】TypeScript 元组

我们知道数组中元素的数据类型都是相同的,如果存储的元素数据类型不同,则需要使用元组。 元组中允许存储不同类型的元素,元组可以作为参数传递给函数。 创建元组的语法格式如下: var tuple_name = [value1,value2,value3,…value n] 声明一个元组并初始化: var mytup…

[转]ListView学习笔记(一)——缓存机制

要想优化ListView首先要了解它的工作原理&#xff0c;列表的显示需要三个元素&#xff1a;ListView、Adapter、显示的数据&#xff1b; 这里的Adapter就是用到了适配器模式&#xff0c;不管传入的是什么View在ListView中都能显示出来。 下面简单说下上图的原理&#xff1a; 1、…

jax-rs jax-ws_Tomcat上具有JAX-WS的Web服务

jax-rs jax-ws让我们假设一家企业正在一个集中式系统中维护用户身份验证详细信息。 我们需要创建一个AuthenticationService&#xff0c;它将获取凭据&#xff0c;对其进行验证并返回状态。 其余的应用程序将使用AuthenticationService对用户进行身份验证。 创建Authentication…

golang反编译_【Golang】脱胎换骨的defer(一)

Go语言的defer是一个很方便的机制&#xff0c;能够把某些函数调用推迟到当前函数返回前才实际执行。我们可以很方便的用defer关闭一个打开的文件、释放一个Redis连接&#xff0c;或者解锁一个Mutex。而且Go语言在设计上保证&#xff0c;即使发生panic&#xff0c;所有的defer调…