设计模式——解释器模式

本文介绍解释器模式。

概念

为语言创建解释器,通常由语言的语法和语法分析来定义。解释器模式,提供了评估语言语法或表达式的方式。解决了反复出现的设计问题,指导设计灵活可重用的面向对象的软件。

结构和工作原理

解释器用来解析语法或者文法,而语法、文法由终结符和非终结符组成。终结符一般为被计算的值或者词,非终结符一般为运算符或者关键字。

  • 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 "+":
// it's necessary to remove first the right operand from the stack
right = stack.pop();
// ..and then the left one
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

Author: nopainanymore
Link: http://nopainanymore.me/DesignPattern-Interpreter/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
wechat