假设系统的一个文本框中,允许用户输入字符串表达式如"5除 2 乘3模4乘6",要求系统能够按照Java的整数乘除运算规则,计算出表达式结果,如12。
假设系统的一个文本框中,允许用户输入字符串表达式如“list 姓名 年龄 学号 sortby 学号”, 要求系统能够从数据库中提取学生信息并按照学号排序。
当应用程序中频繁使用某种文本形式的句子(不管是用户输入的还是从文件中读取的)时,我们需要为定义字符串表达式的语言设计一个解释器(interpreter)。
在实际的应用程序开发中,编写一个解释器的机会较少。而且编写复杂的解释器需要学习《编译原理》。因而yqj2065认为解释器模式(Interpreter Pattern) 是所有设计模式中最难学习的。如果你大致了解《编译原理》方面的知识,其难度系数从7颗星降到4星。因此下一节的内容难度也就4星。
介绍解释器模式的例子,通常解释某种简单的表达式语言,如加减法解释器、乘除法解释器或布尔运算解释器。例如用户输入字符串"5除 2 乘3模4乘6",程序可以按照整数int乘除运算规则,计算出表达式结果如12。注:简化起见,先不考虑优先级和括号的使用。另外,程序中实际上处理"5 / 2 * 3 % 4 * 6"字符串。
对于简单的字符串表达式的解释,其实不需要太多词法分析方面的知识。为了集中注意力,我们将表达式语言简化到脑残的程度。
解释器模式(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 ) );
原文:http://blog.csdn.net/yqj2065/article/details/39304013