对每一个角色都给出了详细的职责,而且在类图中给出五个角色之间的关系。这样实现起来也不是很困难了,下面举了一个简单的例子,希望能加深你对解释器模式的理解。
三、举例
来举一个加减乘除的例子吧,实现思路来自于《java与模式》中的例子。每个角色的功能按照上面提到的规范来实现。
//上下文(环境)角色,使用HashMap来存储变量对应的数值
class Context
{
private Map valueMap = new HashMap();
public void addValue(Variable x , int y)
{
Integer yi = new Integer(y);
valueMap.put(x , yi);
}
public int LookupValue(Variable x)
{
int i = ((Integer)valueMap.get(x)).intValue();
return i ;
}
}
//抽象表达式角色,也可以用接口来实现
abstract class Expression
{
public abstract int interpret(Context con);
}
//终结符表达式角色
class Constant extends Expression
{
private int i ;
public Constant(int i)
{
this.i = i;
}
public int interpret(Context con)
{
return i ;
}
}
class Variable extends Expression
{
public int interpret(Context con)
{
//this为调用interpret方法的Variable对象
return con.LookupValue(this);
}
}
//非终结符表达式角色
class Add extends Expression
{
private Expression left ,right ;
public Add(Expression left , Expression right)
{
this.left = left ;
this.right= right ;
}
public int interpret(Context con)
{
return left.interpret(con) + right.interpret(con);
}
}
class Subtract extends Expression
{
private Expression left , right ;
public Subtract(Expression left , Expression right)
{
this.left = left ;
this.right= right ;
}
public int interpret(Context con)
{
return left.interpret(con) - right.interpret(con);
}
}
class Multiply extends Expression
{
private Expression left , right ;
public Multiply(Expression left , Expression right)
{
this.left = left ;
this.right= right ;
}
public int interpret(Context con)
{
return left.interpret(con) * right.interpret(con);
}
}
class Division extends Expression
{
private Expression left , right ;
public Division(Expression left , Expression right)
{
this.left = left ;
this.right= right ;
}
public int interpret(Context con)
{
try{
return left.interpret(con) / right.interpret(con);
}catch(ArithmeticException ae)
{
System.out.println("被除数为0!");
return -11111;
}
}
}
//测试程序,计算 (a*b)/(a-b+2)
public class Test
{
private static Expression ex ;
private static Context con ;
public static void main(String[] args)
{
con = new Context();
//设置变量、常量
Variable a = new Variable();
Variable b = new Variable();
Constant c = new Constant(2);
//为变量赋值
con.addValue(a , 5);
con.addValue(b , 7);
//运算,对句子的结构由我们自己来分析,构造
ex = new Division(new Multiply(a , b), new Add(new Subtract(a , b) , c));
System.out.println("运算结果为:"+ex.interpret(con));
}
}
解释器模式并没有说明如何创建一个抽象语法树,因此它的实现可以多种多样,在上面我们是直接在Test中提供的,当然还有更好、更专业的实现方式。
对于终结符,GOF建议采用享元模式来共享它们的拷贝,因为它们要多次重复出现。但是考虑到享元模式的使用局限性,我建议还是当你的系统中终结符重复的足够多的时候再考虑享元模式。
四、优缺点
解释器模式提供了一个简单的方式来执行语法,而且容易修改或者扩展语法。一般系统中很多类使用相似的语法,可以使用一个解释器来代替为每一个规则实现一个解释器。而且在解释器中不同的规则是由不同的类来实现的,这样使得添加一个新的语法规则变得简单。
但是解释器模式对于复杂文法难以维护。可以想象一下,每一个规则要对应一个处理类,而且这些类还要递归调用抽象表达式角色,多如乱麻的类交织在一起是多么恐怖的一件事啊!
五、总结
这样对解释器模式应该有了些大体的认识了吧,由于这个模式使用的案例匮乏,所以本文大部分观点直接来自于GOF的原著。只是实例代码是亲自实现并调试通过的。
……