本文介绍解释器模式。
概念
为语言创建解释器,通常由语言的语法和语法分析来定义。解释器模式,提供了评估语言语法或表达式的方式。解决了反复出现的设计问题,指导设计灵活可重用的面向对象的软件。
结构和工作原理
解释器用来解析语法或者文法,而语法、文法由终结符和非终结符组成。终结符一般为被计算的值或者词,非终结符一般为运算符或者关键字。
Expression:抽象表达式,接口或者抽象类,用来声明interpret方法, 所有表达式都要实现该方法用来解释对应都文法规则或者元素
Terminal Expression:终结符表达式,实现Expression,用来解析终结符
Nonterminal Expression:非终结符表达式,用来解析文法中的非终结符
Context:上下文,用来存放文法中各个终结符所对应的具体值
解释器模式使用Terminal Expression定义语法中的原子对象,使用Nonterminal Expression对语言对文法进行定义,定义好 Nonterminal Expression之后,可以将Terminal Expression与Nonterminal Expression进行灵活组合,用由Expression实例组成的语法树来表示语言中的例子,以适应不同的语句。
表达式对象由递归的形式组合成为抽象语法树。
解释器模式并不是用来描述如何构建抽象语法树,这部分是由客户端来手动完成或者由解析器自动完成。
代码示例
public class Interpreter { @FunctionalInterface public interface Expr { int interpret (Map<String, Integer> context) ; static Expr number (int number) { return context -> number; } static Expr plus (Expr left, Expr right) { return context -> left.interpret(context) + right.interpret(context); } static Expr minus (Expr left, Expr right) { return context -> left.interpret(context) - right.interpret(context); } static Expr variable (String name) { return context -> context.getOrDefault(name, 0 ); } } private static Expr parseToken (String token, ArrayDeque<Expr> stack) { Expr left, right; switch (token) { case "+" : right = stack.pop(); left = stack.pop(); return Expr.plus(left, right); case "-" : right = stack.pop(); left = stack.pop(); return Expr.minus(left, right); default : return Expr.variable(token); } } public static Expr parse (String expression) { ArrayDeque<Expr> stack = new ArrayDeque<Expr>(); for (String token : expression.split(" " )) { stack.push(parseToken(token, stack)); } return stack.pop(); } }
@Slf4j public class InterpreterClient { public static void main (String[] args) { Interpreter.Expr expr = parse("w x z - +" ); Map<String, Integer> context = new HashMap<>(); context.put("w" , 5 ); context.put("x" , 10 ); context.put("z" , 42 ); Integer result = expr.interpret(context); log.info("InterpreterClient- main- result:{}" , result); } }
参考资料
https://en.wikipedia.org/wiki/Interpreter_pattern
https://juejin.im/post/5ad84374f265da502b5f52d6
https://www.runoob.com/design-pattern/interpreter-pattern.html