简明解释器模式(5.3)

假设系统的一个文本框中,允许用户输入字符串表达式如"5除 2 乘3模4乘6",要求系统能够按照Java的整数乘除运算规则,计算出表达式结果,如12。

假设系统的一个文本框中,允许用户输入字符串表达式如“list 姓名 年龄 学号 sortby 学号”, 要求系统能够从数据库中提取学生信息并按照学号排序。

当应用程序中频繁使用某种文本形式的句子(不管是用户输入的还是从文件中读取的)时,我们需要为定义字符串表达式的语言设计一个解释器(interpreter)

在实际的应用程序开发中,编写一个解释器的机会较少。而且编写复杂的解释器需要学习《编译原理》。因而yqj2065认为解释器模式(Interpreter Pattern) 是所有设计模式中最难学习的。如果你大致了解《编译原理》方面的知识,其难度系数从7颗星降到4星。因此下一节的内容难度也就4星。

7.1.1 乘法解释器

介绍解释器模式的例子,通常解释某种简单的表达式语言,如加减法解释器、乘除法解释器或布尔运算解释器。例如用户输入字符串"5除 2 乘3模4乘6",程序可以按照整数int乘除运算规则,计算出表达式结果如12。注:简化起见,先不考虑优先级和括号的使用。另外,程序中实际上处理"5 / 2 * 3 % 4 * 6"字符串。

对于简单的字符串表达式的解释,其实不需要太多词法分析方面的知识。为了集中注意力,我们将表达式语言简化到脑残的程度。

  • 乘除法表达式由数字和操作符‘*‘,‘/‘,‘%‘构成。
  • 数字是表达式,用操作符连接两个数字是表达式,递归地,用操作符连接两个表达式是表达式。所以,258,2*5,2*5/6都是合法的表达式。
  • 简单起见,表达式语言要求数字和操作符之间必须有至少一个空格。因此代码 String[] tokens= statement.split("\\s+");

    可以容易地将用户输入的字符串分割成表达式语言的最小单元——终结符(terminal)。

解释器模式(Interpreter Pattern)的核心是解释表达式,接口Expr代表/封装表达式,Expr封装了一个interpret()方法,对本表达式(Expr实例)进行解释(计算) 并返回计算的结果。

数字Digit是表达式,所以Digit是Expr的子类型;用操作符连接两个数字是表达式,以Op表示这种表达式,而而MulOp、ModOP和DivOP分别表示乘、模、除表达式。

例程 7 3封装文法
package intent.interpreter.calculator;
public interface Expr{
	public int interpret();
}

package intent.interpreter.calculator;
public abstract class Op implements Expr{
	protected Expr left,right;//
	public Op(Expr left,Expr right)	{
		this.left=left;		this.right=right;
	}
}

package intent.interpreter.calculator;
public class MulOp extends Op{
	public MulOp(Expr left,Expr right)	{
		super(left,right);
	}
	@Override public int interpret()	{
		return super.left.interpret() * super.right.interpret();
	}
}

package intent.interpreter.calculator;
public class Digit implements Expr{
	private int value;
	public Digit(int value)	{
		this.value=value;
	}
	@Override public int interpret()	{
		return this.value;
	}
}

单纯看Expr与Digit和Op的类图,和组合模式、装饰模式完全一样的结构。区别和内在联系后面讨论。

现在,各个零部件都有了,但是整个"5 / 2 * 3 % 4 * 6"字符串还需要形成一个表达式。一个简洁的实现是使用构造语法树。

例程 7 4构造语法树
package intent.interpreter.calculator;
import java.util.*;
public class Calculator{
    private Expr expr;
    public void build(String statement){
        String[] tokens=statement.split(" ");
        Expr left=null,right=null;
        Stack<Expr> stack=new Stack<>();
        for(int i=0;i<tokens.length;i++){
            if(tokens[i].equals("*")){
                left= stack.pop();
                right=new Digit(tokens[++i]);
                stack.push(new MulOp(left,right));
            } else if(tokens[i].equals("/")){
                left= stack.pop();
                right=new Digit(tokens[++i]);
                stack.push(new DivOp(left,right));
            }else if(tokens[i].equals("%")){
                left= stack.pop();
                right=new Digit(tokens[++i]);
                stack.push(new ModOp(left,right));
            }else {
                stack.push(new Digit(tokens[i]));
            }
        }
        this.expr=(Expr)stack.pop();
    }

    public int compute(){
        return expr.interpret();
    }
}

public class Client{
	public static void main(String args[])	{
		String statement = "6 / 2 * 3 % 4 * 6";
		statement = "62 / 3";
		Calculator calculator = new Calculator();
		calculator.build(statement);
		int result = calculator.compute();
		System.out.println(statement + " = " + result);
	}
	public static void test()	{
	    Expr e = new DivOp(new Digit(62),new Digit(3));
	    int result = e.interpret();
		System.out.println(" 62 / 3 = " + result);
	}
}

[设计模式]中的解释器模式并未解释如何创建一个抽象的语法树。

Calculator的方法build(String statement)将参数statement解析并构造一个Expr实例。

也可以直接由Client直接定义Expr实例,如test()代码所示,并执行其interpret()。这样纯手工的玩意,看上去蛮有趣和亲切的——因为傻傻的。

Expr e = new DivOp ( new Digit(62),new Digit(3 ) );

时间: 2024-12-10 04:04:49

简明解释器模式(5.3)的相关文章

简明解释器模式-2

简明解释器模式(5.3)续 本节介绍一门新的表达式语言.用户输入代数表达式,如"(a*a+b)*(c-d)",程序按照优先级和括号的使用情况计算正确的结果. 1 一门语言,按照严格定义的规则,可以产生无穷多样的句子.描述语言的规则称为文法/语法.文法由四个元素构成,表示为一个四元组:G = {ST,SN,S,P}. ①终结符(terminal)的集合ST.终结符是语言的最小文法元素(token/语言符号).前面一个例子中,终结符是(长度不限的)数字和操作符.本例,终结符是字母Alpha

解释器模式 Interpreter

代码例子 参考 1.解释器模式定义 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 说明:解释器模式设计到文法规则和抽象语法树. 2.解释器模式的结构 解释器模式包含四个角色: 1)抽象表达式(AbstractExpress):声明抽象的解释操作,它是所有终结符表达式和非终结符表达式的公共父类. 2)终结符表达式(TerminalExpress):是抽象表达式的子类,实现了与文法中的终结符相关联的解释操作,句子中的每一个终结符都是该类的一个实例.

[工作中的设计模式]解释器模式模式Interpreter

一.模式解析 解释器模式是类的行为模式.给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器.客户端可以使用这个解释器来解释这个语言中的句子. 以上是解释器模式的类图,事实上我很少附上类图,但解释器模式确实比较抽象,为了便于理解还是放了上来,此模式的要点是: 1.客户端提供一个文本.表达式或者其他,约定解析格式 2.针对文本中可以分为终结符表达式和非终结符表达式, 3.终结符表达式无需进一步解析,但仍需要转化为抽象接口的实例 4.针对非终结表达式,没一种标示需要定义一种解

学习日记之解释器模式和Effective C++

解释器模式(interpreter):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. (1),如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言的句子.这样可以构建一个解释器,该解释器通过解释这些句子来解决该问题. (2),当一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象的语法树时,可使用解释器模式. (3),容易改变和扩展文法,因为该模式使用类来表示文法规则,你可以使用继承来改变和扩展该文法

Head First设计模式之解释器模式

一.定义 给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子. 主要解决:对于一些固定文法构建一个解释句子的解释器. 何时使用:如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子.这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题. 如何解决:构件语法树,定义终结符与非终结符. 二.结构 组成: AbstractExpression(抽象表达式):定义解释器的接口,约定解释器的解释操作. Termi

Java解释器模式`

解释器模式提供了一种评估计算语言语法或表达式的方法. 这种类型的模式属于行为模式. 这种模式涉及实现一个表达式接口,它告诉解释一个指定的上下文. 此模式用于SQL解析,符号处理引擎等. 实现示例 我们将创建一个接口Expression并且在具体的类实现这个Expression接口. 定义了一个TerminalExpression类,用作所讨论的上下文的主解释器. 其他的类 - OrExpression和AndExpression用于创建组合表达式. InterpreterPatternDemo这

《JAVA与模式》之解释器模式

解释器模式是类的行为模式.给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器.客户端可以使用这个解释器来解释这个语言中的句子. 解释器模式的结构 下面就以一个示意性的系统为例,讨论解释器模式的结构.系统的结构图如下所示: 模式所涉及的角色如下所示: (1)抽象表达式(Expression)角色:声明一个所有的具体表达式角色都需要实现的抽象接口.这个接口主要是一个interpret()方法,称做解释操作. (2)终结符表达式(Terminal Expression)角色:

解释器模式(Interpreter Pattern)

解释器模式:为语言创建解释器,提供评估语言的语法或表达式的方法. 例子: public interface Expression { public abstract boolean interpret(String context); } public class TerminalExpression implements Expression { private String data; public TerminalExpression(String data) { this.data =

行为型模式之解释器模式

概述 解释器模式是一种使用频率相对较低但学习难度较大的设计模式,它用于描述如何使用面向对象语言构成一个简单的语言解释器.在某些情况下,为了更好地描述某一些特定类型的问题,我们可以创建一种新的语言,这种语言拥有自己的表达式和结构,即文法规则,这些问题的实例将对应为该语言中的句子.此时,可以使用解释器模式来设计这种新的语言.对解释器模式的学习能够加深我们对面向对象思想的理解,并且掌握编程语言中文法规则的解释过程 定义 解释器模式(Interpreter Pattern):定义一个语言的文法,并且建立