0x0、引言
本文对应设计模式与范式:行为型(72),解释器模式 (Interpreter Pattern),用来描述如何构建一个简单的 "语言"解释器。
比命令模式更小众,只有在特定领域才会用到,如编译器、规则引擎、正则表达式、SQL等,而这类语言又称 领域特定语言 (Domain Specific Language, DSL)。
工作中很少会让我们去编写一个解释器,了解下即可,主要是借鉴思想 如何通过更简洁的规则来表示复杂逻辑。
Tips:二手知识加工难免有所纰漏,感兴趣有时间的可自行查阅原文,谢谢。
0x1、定义
原始定义
为某个语言定义它的语法(文法)表示,并定义一个解释器用来处理这个语法。
有点懵逼,没事,先来看下它的四个组成角色:
- AbstractExpression (抽象表达式) → 定义一个解释器有哪些 解释操作,具体类实现还分 终结符解释器 和 非终结符解释器。
- TerminalExpression (终结符表达式) → 实现 文法中元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。终结符一般是文法中的运算单元,如简单公式R=R1+R2,其中的R1和R2就是终结符,对应R1和R2的解释器就是终结符表达式;
- NonterminalExpression (非终结符表达式) → 文法中的每条规则 对应于一个非终结符表达式,一般是文法中的运算符或其他关键字。如R=R1+R2里的+就是非终结符,解释+的解释器就是非终结符表达式。它会根据逻辑的复杂度增加而增加,原则上每个文法规则都对应一个非终结符表达式。
- Context (上下文环境) → 存放各个终结符对应的具体值,还是R=R1+R2,给R1赋值100,给R2赋值200,这些信息需存放到环境角色中,很多情况下使用Map充当环境角色就够了~
直接画出UML类图
网络异常,图片无法展示
|
0x2、写个简单例子
定义一个能解释加减法的解释器为例子~
// 抽象表达式 public abstract class AbstractExpression { public abstract int interpreter(Context context); @Override abstract public String toString(); } // 上下文环境 public class Context { private Map<AbstractExpression, Integer> map = new HashMap<>(); public void addExpression(AbstractExpression expression, int value) { map.put(expression, value); } public int lookup(AbstractExpression expression) { return map.get(expression); } } // 终结符表达式(常量与变量) public class ConstantExpression extends AbstractExpression { private int value; public ConstantExpression(int value) { this.value = value; } @Override public int interpreter(Context context) { return value; } @Override public String toString() { return Integer.toString(value); } } public class VariableExpression extends AbstractExpression { private String name; public VariableExpression(String name) { this.name = name; } @Override public int interpreter(Context context) { return context.lookup(this); } @Override public String toString() { return name; } } // 非终结符表达式(加法和减法) public class PlusExpression extends AbstractExpression { private final AbstractExpression leftExpression; private final AbstractExpression rightExpression; public PlusExpression(AbstractExpression leftExpression, AbstractExpression rightExpression) { this.leftExpression = leftExpression; this.rightExpression = rightExpression; } @Override public int interpreter(Context context) { return leftExpression.interpreter(context) + rightExpression.interpreter(context); } @Override public String toString() { return leftExpression.toString() + " + " + rightExpression.toString(); } } public class MinusExpression extends AbstractExpression { private final AbstractExpression leftExpression; private final AbstractExpression rightExpression; public MinusExpression(AbstractExpression leftExpression, AbstractExpression rightExpression) { this.leftExpression = leftExpression; this.rightExpression = rightExpression; } @Override public int interpreter(Context context) { return leftExpression.interpreter(context) - rightExpression.interpreter(context); } @Override public String toString() { return leftExpression.toString() + " - " + rightExpression.toString(); } } // 测试用例 public class Client { public static void main(String[] args) { Context context = new Context(); AbstractExpression a = new VariableExpression("a"); AbstractExpression b = new VariableExpression("b"); AbstractExpression c = new VariableExpression("c"); context.addExpression(a, 6); context.addExpression(b, 8); context.addExpression(c, 16); AbstractExpression e1 = new PlusExpression(a, b); System.out.println(e1 + " = " + e1.interpreter(context)); AbstractExpression e2 = new PlusExpression(e1, c); System.out.println(e2 + " = " + e2.interpreter(context)); AbstractExpression e3 = new MinusExpression(e2, new ConstantExpression(7)); System.out.println(e3 + " = " + e3.interpreter(context)); AbstractExpression e4 = new MinusExpression(e3, b); System.out.println(e4 + " = " + e4.interpreter(context)); } }