解释器模式是一种行为模式,比较通用的定义“给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子”。spring的express中就使用了这种设计模式。
解释器模式的本质就是解释自定义了的语言,其中涉及三个概念:表达式(Expression)、解释器(Interpreter)和环境(Context)。
解释器模式大致分为三个过程:首先,定义一种语言,并定义这种语言的一种文法表现——可以理解为一个运算表达式(Expression);然后,定义解释器(Interpreter)来解释自定义运算表达式;解释器在解释表达式的过程中可能遇到一些变量,而这些变量的值就存储在环境(Context)中,简单的做法是使用Map将变量名和变量值对应起来。
先来看表达式,表达式分为:终结表达式(Terminal Expression)和非中介表达式(NonTerminal Expression)。
1、终结表达式:文法中的每一个终结符都有一个具体终结表达式与之相对应。比如有一个简单的公式R=R1+R2,在里面R1和R2就是终结符。通常运行表达式中的常量和变量都是终结表达式,蕴含了着到此就终结了,不用再运算了。
2、非终结表达式:文法中的每一条规则都需要一个具体的非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,“+"就是非终结符,解析“+”的解释器就是一个非终结符表达式。
在具体实现时,需要抽象一个表达式(Expression)抽象类,终结表达式和非终结表达式都继承该表达式抽象类。
public abstract class Expression { } public class TerminalExpression extends Expression{ } public class NonTerminalExpression extends Expression{ }
再来看解释器,解释器需要提供一个解释方法(interpret)负责文法/表达式的解释工作。解释器模式中将解释器与表达式绑定起来,来表明表达式用该解释器来解释自己。具体实现方式是在表达式中添加解释方法(interpret),表达式可以自己解释自己,无需外部担心。
public class Context{ } public abstract class Expression { public abstract Object interpret(Context context); } public class TerminalExpression extends Expression{ public Object interpret(Context context){} } public class NonTerminalExpression extends Expression{ public Object interpret(Context context){} }
在解释表达式的过程中可能要替换“变量”,因此定义了Context(环境)类,interpret解释方法接收Context类型的参数。
在解释器模式中通常还会遇到一个问题,就是递归解释。下面用一个简单的示例,来说明如何使用解释器模式,同时也展示了递归解释。示例定义一个简单加法运算,AndExpression加运算表达式同时解释加运算,VariableExpression变量表达式同时解释变量值:
public class Context { private Map<String,Integer> map = new HashMap<String,Integer>(); public void put(String key, int value){ map.put(key, value); } public int lookup(String key){ return map.get(key); } }
public abstract class Expression { public abstract int interpret(Context context); }
//TerminalExpression public class VariableExpression extends Expression{ private String key; public VariableExpression(String key){ this.key = key; } @Override public int interpret(Context context) { return context.lookup(key); } }
//NonTerminalExpression public class AndExpression extends Expression{ private Expression left; private Expression right; public AndExpression(Expression left, Expression right){ this.left = left; this.right = right; } @Override public int interpret(Context context) { //递归解释 return left.interpret(context) + right.interpret(context); } }
public class ExpressionMain { public static void main(String[] args){ VariableExpression one = new VariableExpression("one"); VariableExpression two = new VariableExpression("two"); VariableExpression three = new VariableExpression("three"); AndExpression first = new AndExpression(one, two); AndExpression second = new AndExpression(first, three); Context context = new Context(); context.put("one", 1); context.put("two", 2); context.put("three", 3); System.out.println(second.interpret(context)); } }