本文是我们名为“ Java设计模式 ”的学院课程的一部分。
在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因,并了解何时以及如何应用模式中的每一个。 在这里查看 !
目录
- 1.简介 2.什么是口译员设计模式 3.实施口译员设计模式 4.何时使用口译员设计模式 5. JDK中的解释器设计模式 6.下载源代码
1.简介
口译员设计模式是一种重型模式。 这一切都是关于通过创建针对自己的编程语言的解释器来组合自己的编程语言,或处理现有的编程语言。 要使用这种模式,您必须对正规语法有一定的了解,才能将一种语言组合在一起。 可以想象,这是开发人员每天都不会真正使用的模式之一,因为创建自己的语言并不是很多人要做的事情。
例如,就形式语法而言,以新语言定义表达式可能类似于以下代码片段:
expression ::= <command> | <repetition> | <sequence>
那么,使用新语言的每个表达式可能由命令,命令的重复和序列表达式组成。 每个项目都可以使用解释方法表示为一个对象,以将您的新语言翻译成可以在Java中运行的语言。
为了说明解释器设计模式的用法,我们创建一个示例来解决简单的数学表达式,但在此之前,让我们在下面的部分中讨论有关解释器设计模式的一些详细信息。
2.什么是口译员设计模式
给定一种语言,请定义其语法的表示形式,以及使用该表示形式来解释该语言句子的解释器。
通常,语言由一组语法规则组成。 遵循这些语法规则可以构建不同的句子。 有时应用程序可能需要处理重复出现的相似请求,这些请求是一组语法规则的组合。 这些请求是不同的,但从某种意义上来说它们是相似的,因为它们都是使用同一组规则构成的。
一个简单的例子就是提交给计算器程序的一组不同的算术表达式。 尽管每个这样的表达式都不同,但是它们都是使用构成算术表达式语言语法的基本规则构造的。
在这种情况下,代替将每个不同的规则组合视为一个单独的案例,对应用程序来说,具有解释规则的通用组合的能力可能是有益的。 解释器模式可用于在应用程序中设计此功能,以便其他应用程序和用户可以使用由一组语法规则定义的简单语言来指定操作。
可以将类层次结构设计为表示语法规则集,而层次结构中的每个类都表示一个单独的语法规则。 可以将解释器模块设计为解释使用上面设计的类层次结构构造的句子,并执行必要的操作。
由于每个语法规则都代表一个不同的类别,因此类别的数量会随着语法规则的数量而增加。 具有广泛而复杂的语法规则的语言需要大量的类。 语法简单时,解释器模式最有效。 具有简单的语法避免了需要具有许多与所涉及的复杂规则集相对应的类,而这些类很难管理和维护。
抽象表达
- 声明抽象语法树中所有节点共有的抽象
Interpret
操作。
终端表达
- 实现与语法中的终端符号关联的
Interpret
操作。 - 句子中每个终端符号都需要一个实例。
非末端表达
- 语法中的每个规则
R ::= R1 R2 ... Rn
都需要一个这样的类。 - 为每个符号
R1
到Rn
维护类型AbstractExpression
实例变量。 - 为语法中的非终结符实现
Interpret
操作。Interpret
通常对表示R1
到Rn
的变量进行递归调用。
语境
- 包含解释器的全局信息。
客户
- 构建(或给定)抽象语法树,该语法树以语法定义的语言表示特定的句子。 抽象语法树是根据
NonterminalExpression
和TerminalExpression
类的实例组装而成的。 - 调用
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
。 在逐个迭代令牌时,首先我们检查了令牌是运算符还是操作数。 如果令牌是操作数,则将其推入堆栈,但如果是运算符,则从堆栈中弹出前两个操作数。 ExpressionUtils
的getOperation
方法根据传递给它的运算符返回适当的表达式类。
然后,我们解释结果并将其推回堆栈。 迭代完整的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