Scala设计模式UML图例和代码实现实战 行为模式--解释器设计模式

Scala解释器设计模式

在现代编程中,我们有时必须处理来自易于理解和定义明确的域的问题。在某些情况下,使用语言表示域是有意义的,这样可以使用解释器轻松解决问题。
解释器设计模式对于指定如何使用类来表示语句并构建语法树来评估语言表达式非常有用。
解释器设计模式也使用复合设计模式。解释器的一些常见用途是语言解析,协议等。
示例类图创建语言和语法是一项复杂的任务,在进入它之前,开发人员应该确信它确实值得付出努力。它需要非常好地理解正在建模的域,并且通常需要一些时间。在本节中,我们将介绍有关程序的解释器部分的类图,该程序以反向波兰表示法解析和评估表达式。这是计算机科学中的一个重要概念,它显示了计算机在执行不同操作时的实际工作方式。屏幕截图如下所示:我们语言的主要概念是Expression。一切都是表达,正在被解释。
我们可以在图中区分两种主要类型的表达式:终端表达式:这是Number类。在构建表达式的语法树时,它是一个终端,它没有其他子节点(叶节点)。
非终结表达式:这些是Add,Subtract和Multiply类。它们具有子表达式,这就是整个语法树的构建方式。
上面的屏幕截图仅显示解释器将转换我们的语言的那些表达式。在下面的小节中,我们将另外显示可以使这样的应用程序工作的所有其他类。
代码示例在这里,我们将逐步显示解释器应用程序的代码。我们目前有一些限制,例如只支持整数,没有良好的错误报告机制,只有三个操作,但很容易添加新的操作。你可以尝试在我们已有的基础上进行构建。

##首先,让我们看一下基本的表达特征

特征表达式{def interpret():Int}
它非常简单,并且包含一个其他表达式必须实现的方法。终结表达式,我们的Number类,如下所示:
class Number(n:Int)extends Expression {override def interpret():Int = n}
它没有做任何特殊的事情 - 只返回它携带的数字解释被称为。非终结表达式有更多的代码,但它们都非常简单:

类添加(右:表达式,左:表达式)扩展表达式{覆盖def解释():

Int = left.interpret()right.interpret()} c lass Subtract(右:Expression,left:Expression)extends Expression {override def interpret():Int = left.interpret() - right.interpret()} class Multiply(right:Expression,left:Expression)extends Expression {override def interpret():Int = left.interpret()* right.interpret()}

到目前为止,这是我们在图中显示的所有内容,它是解释器设计模式的基本部分。有些人可能会注意到构造函数中的任何地方,我们首先使用右手表达式,然后是左手表达式。这是有目的地完成的,因为当我们实际实现我们的解析器时,它会使代码更加清晰。
从现在开始,我们将展示如何在实际应用程序中解析和使用设计模式。首先,我们需要创建一个基于令牌的工厂,该工厂决定应该返回哪个表达式:
object Expression {def apply(operator:String,left:=> Expression,right:=> Expression):Option [Expression ] = operator match {case“”=> Some(new Add(right,left))case“ - ”=> Some(new Subtract(right,left))case“*”=> Some(new Multiply(right,left) ))case i if i.matches(“\ d”)=> Some(new Number(i.toInt))case _ => None}}

在前面的代码中,我们应用了一些技术和设计模式已经通过工厂和名称参数。后者非常重要,因为基于这种情况,我们的代码命中决定了它们是否会被评估。

trait Expression {
def interpret(): Int
}

class Add(right: Expression, left: Expression) extends Expression {
override def interpret(): Int = left.interpret() + right.interpret()
}

class Subtract(right: Expression, left: Expression) extends Expression {
override def interpret(): Int = left.interpret() - right.interpret()
}

class Multiply(right: Expression, left: Expression) extends Expression {
override def interpret(): Int = left.interpret() * right.interpret()
}

class Number(n: Int) extends Expression {
override def interpret(): Int = n
}

object Expression {
def apply(operator: String, left: => Expression, right: => Expression): Option[Expression] =
operator match {
case “+” => Some(new Add(right, left))
case “-” => Some(new Subtract(right, left))
case “*” => Some(new Multiply(right, left))
case i if i.matches("\d+") => Some(new Number(i.toInt))
case _ => None
}
}

import java.util.StringTokenizer

import scala.collection.JavaConverters._
import scala.collection.mutable

class RPNParser {

def parse(expression: String): Expression = {
val tokenizer = new StringTokenizer(expression)
tokenizer.asScala.foldLeft(mutable.StackExpression) {
case (result, token) =>
val item = Expression(token.toString, result.pop(), result.pop())
item.foreach(result.push)
result
}.pop()
}
}

class RPNInterpreter {
def interpret(expression: Expression): Int = expression.interpret()
}

object RPNExample {
def main(args: Array[String]): Unit = {
val expr1 = “1 2 + 3 * 9 10 + -” // (1 + 2) * 3 - (9 + 10) = -10
val expr2 = “1 2 3 4 5 * * - +” // 1 + 2 - 3 * 4 * 5 = -57
val expr3 = “12 -” // invalid
val parser = new RPNParser
val interpreter = new RPNInterpreter

System.out.println(s"The result of '${expr1}' is: ${interpreter.interpret(parser.parse(expr1))}")
System.out.println(s"The result of '${expr2}' is: ${interpreter.interpret(parser.parse(expr2))}")
try {
  System.out.println(s"The result is: ${interpreter.interpret(parser.parse(expr3))}")
} catch {
  case _: Throwable => System.out.println(s"'$expr3' is invalid.")
}

}
}
Scala设计模式UML图例和代码实现实战 行为模式--解释器设计模式