定义
解释器模式(Interpreter Pattern)是一种按照规定语法对表达式进行解析的方案,在项目中较少使用。
英文:Given a language,define a representation for its grammer along with an interpreter that uses the representation to interpret that uses the representation to interpret sentences in the language.
翻译:给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示方法来解释语言中的句子。
角色
抽象表达式(Abstract Expression)角色:该角色声明一个所有的具体表达式角色都需要实现的抽象接口,该接口主要是含有一个解释操作interpreter()操作。
终结符表达式(Terminal Expression)角色:该角色实现了抽象表达式角色所要求的接口,文法中的每一个终结符都会有一个具体终结表达式与之相对应。
非终结符表达式(Nonterminal Expression)角色:该角色是一个具体角色,文法中的每一条规则都对应一个非终结符表达式类。
环境角色(Context)角色:该角色提供解释器之外的全局信息。
客户端(Client)角色:该角色创建一个抽象语法树,调用解释操作方法。
/** * 抽象表达式. */ public abstract class AbstractExpression { //每个表达式必须有一个解析任务 public abstract Object interpreter(); } /** * 终结符表达式 */ public class TerminalExpression extends AbstractExpression { //通常终结符表达式只有一个,但是有多个对象 @Override public Object interpreter() { return null; } } /** * 非终结符表达式 */ public class NonterminalExpression extends AbstractExpression { //每个非终结符表达式都会对其他表达式产生依赖 public NonterminalExpression(AbstractExpression expression) { } @Override public Object interpreter() { //进行文法处理 return null; } } /** * 环境角色 */ public class Context { private HashMap map = new HashMap(); //用来容纳所有表达式 }
//通常Client是一个封装类,封装的过程就是传递进来一个规范语法文件,解释器分析后产生结果并返回,避免调用者与语法解释器的耦合关系 public class Client { Context context = new Context(); public static void main(String[] args) { for(;;){ //进行语法判断,并产生递归调用 } } }
优点
- 简单的语法分析工具。
- 扩展性良好,若修改语法规则,只要修改相应的非终结符表达式即可,若扩展语法,只要增加非终结符类即可。
缺点
- 解释器模式会引起类膨胀。每个语法都要产生一个非终结符表达式,语法比较复杂时就可能产生大量的类文件,不易维护。
- 采用递归调动方法。每个非终结符表达式只关心与自己有关的表达式,每个表达式想要知道最终的结果,必须一层一层地剥茧,无论是面向过程的语言还是面向对象的语言,递归都是在必要条件下才使用的,它使程序不易调试且影响效率。
使用场景
- 重复发生的问题可以使用解释器模式。例如:多个应用服务器,每天产生大量的日志,系统需要对日志文件进行分析处理,由于各个服务器的日志格式不同,但是数据要素是相同的,按照解释器的说法就是终结符表达式都是相同的,非终结符表达式就需要制定。
- 一个简单语法需要解释的场景。
/** * 抽象解释器 */ public interface ArithmeticExpression { int interpret(Variables variables); } /** * 算数表达式中的变量--终结符角色 */ public class Variable implements ArithmeticExpression { @Override public int interpret(Variables variables) { return variables.get(this); } } /** * 加算法--非终结符角色 */ public class Plus implements ArithmeticExpression { ArithmeticExpression left; //终结符角色 ArithmeticExpression right; //终结符角色 public Plus(ArithmeticExpression left, ArithmeticExpression right) { this.left = left; this.right = right; } /** * 操作终结符角色 * @param variables * @return */ @Override public int interpret(Variables variables) { //终结符角色.interpret(环境角色)-->环境角色.get(this)获取终结符角色在环境角色中注册的值 return left.interpret(variables)+right.interpret(variables); } } /** * 减法--非终结符角色 */ public class Substract implements ArithmeticExpression{ ArithmeticExpression left; //终结符角色 ArithmeticExpression right; //终结符角色 public Substract(ArithmeticExpression left, ArithmeticExpression right) { this.left = left; this.right = right; } @Override public int interpret(Variables variables) { //终结符角色.interpret(环境角色)-->环境角色.get(this)获取终结符角色在环境角色中注册的值 return left.interpret(variables)-right.interpret(variables); } } /** * 乘算法--非终结符角色 */ public class Multiply implements ArithmeticExpression { ArithmeticExpression left; //终结符角色 ArithmeticExpression right; //终结符角色 public Multiply(ArithmeticExpression left, ArithmeticExpression right) { this.left = left; this.right = right; } @Override public int interpret(Variables variables) { //终结符角色.interpret(环境角色)-->环境角色.get(this)获取终结符角色在环境角色中注册的值 return left.interpret(variables)*right.interpret(variables); } } /** * 除算法--非终结符角色 */ public class Division implements ArithmeticExpression { ArithmeticExpression left; //终结符角色 ArithmeticExpression right; //终结符角色 public Division(ArithmeticExpression left, ArithmeticExpression right) { this.left = left; this.right = right; } @Override public int interpret(Variables variables) { //终结符角色.interpret(环境角色)-->环境角色.get(this)获取终结符角色在环境角色中注册的值 return left.interpret(variables)/right.interpret(variables); } } /** * 环境角色--使用Map存储各个变量的值 */ public class Variables { //key为变量类型,value为变量值.Variable为封装int的包装类 Map<Variable,Integer> v = new HashMap<Variable,Integer>(); //封装值,将终结符及其对应的解释封装到环境角色 public void put(Variable variable,int value){ v.put(variable,value); } //取值,从环境角色中取出非终结符对应的值 public int get(Variable variable){ return v.get(variable); } } public class Main { public static void main(String[] args) { Variables v = new Variables(); //环境角色 //终结符 Variable x = new Variable(); Variable y = new Variable(); Variable z = new Variable(); //将终结符注册到环境中 v.put(x,10); v.put(y,20); v.put(z,30); //计算x*(y+z/x)-x //非终结符接口 = new 非终结符(终结符,终结符),将两个终结符注册到非终结符中操作 ArithmeticExpression e = new Substract(new Multiply(x,new Plus(y,new Division(z,x))),x); //解析非终结符接口 => 非终结符成员变量(终结符)相互操作 => 终结符.interpret(环境角色) => 环境角色.get(this)获取终结符代表的值,拿这些值进行操作 int result = e.interpret(v); System.out.println(result); } }
个人总结
终结符实现抽象表达式的接口,interpert(环境角色)解析自身代表的value。
非终结符实现抽象表达式接口,interpert(环境角色)解析终结符代表的的value相互操作的结果。