目录
1. 解释器模式
1.1 定义、优缺点、适应场景
- 1. 解释器模式
- 1.1 定义、优缺点、适应场景
- 1.2 模式的结构与实现
定义:解释器模式(Interpreter Pattern),是指给定一个语言(表达式),来表示它的文法,并定义一个解释器,使用该解释器来解释语言中的句子(表达式),并得到结果。例如在编译原理中,一个算术表达式通过词法分析器形成词法单元,而后这些词法单元再通过语法分析器构建成一颗抽象语法分析树。这里的词法分析器和语法分析器都可以看做是解释器
优点:
- 易于扩展文法。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来扩展文法
- 每一条文法规则都可以表示为一个类,因此可以方便地实现一个简单的语言
- 增加新的解释表达式较为方便。如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合开闭原则
缺点:
- 解释器模式会引起类膨胀
- 解释器模式采用递归调用方法,将会导致调试非常复杂、效率可能降低
适应场景:
- 应用可以将一个需要解释执行的语言中的句子表示为一个抽象语法树,让程序具有良好的扩展性
- 一些重复出现的问题可以用一种简单的语言来表达
- 一个简单语法需要解释的场景
- 比如编译器、运算表达式计算、正则表达式、机器人等
结构:
- 环境角色(Context): 含有解释器之外的全局信息
- 抽象表达式(AbstractExpression): 声明一个抽象的解释方法,这个方法为抽象语法树中所有的节点所共享
- 终结符表达式(TerminalExpression): 实现与文法中的终结符相关的解释操作
- 非终结符表达式(NonTermialExpression): 为文法中的非终结符实现解释操作
- Client:通过Client输入Context和TerminalExpression信息
实现:
通过解释器模式来实现整数四则运算,如计算a+b-c的值,具体要求
- 先输入表达式的形式,比如a+b+c-d+e, 要求表达式的字母不能重复
- 再分别输入a ,b, c, d, e的值
- 最后求出结果
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Stack;
public class InterpreterTest {
public static void main(String[] args) throws IOException {
// 例如:expStr = a+b-c
String expStr = getExpStr();
// 例如:inputMap = {a=10, b=30, c=20}
HashMap inputMap = getInputMap(expStr);
// 进行计算器表达式的构造
Calculator calculator = new Calculator(expStr);
// 将inputMap传入计算器表达式,进行计算
System.out.println("运算结果:" + expStr + " = " + calculator.run(inputMap));
}
// 获取用户输入的字符串表达式
public static String getExpStr() throws IOException {
System.out.print("请输入表达式:");
return (new BufferedReader(new InputStreamReader(System.in))).readLine();
}
// 获得用户输入的字符串表达式,各个变量及其值HashMap
public static HashMap getInputMap(String expStr) throws IOException {
HashMap hashMap = new HashMap();
for (char ch : expStr.toCharArray()) {
if (ch != '+' && ch != '-' && ch != ' ') {
// hashMap右的变量则不处理
if (!hashMap.containsKey(String.valueOf(ch))) {
System.out.print("请输入" + String.valueOf(ch) + "的值:");
String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
hashMap.put(String.valueOf(ch), Integer.valueOf(in));
}
}
}
return hashMap;
}
}
// 抽象表达式-变量表达式和运算符表达式的父类
abstract class Expression {
// 由子类进行具体的实现
// 如果是变量表达式子类,则从HashMap通过key获取值
// 如果是运算符表达式子类,则进行运算符操作。如果运算符左右两边还是运算符表达式,则递归调用
public abstract int interpreter(HashMap inputMap);
}
// 终结符表达式-变量表达式
class VarExpression extends Expression {
// 变量的key
private String key;
public VarExpression(String key) {
this.key = key;
}
// 从HashMap通过key获取值
@Override
public int interpreter(HashMap inputMap) {
return inputMap.get(this.key);
}
}
// 非终结符表达式-运算符表达式
class SymbolExpression extends Expression {
// 左右表达式,可以是值表达式,也可以是运算符表达式
protected Expression left;
protected Expression right;
public SymbolExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
// 具体的实现由子类去实现。这里只提供默认实现
@Override
public int interpreter(HashMap inputMap) {
return 0;
}
}
// 非终结符表达式具体实现-加法表达式
class AddExpression extends SymbolExpression {
public AddExpression(Expression left, Expression right) {
super(left, right);
}
// 进行加法运算符操作。如果运算符左右两边是值表达式,则从HashMap获取值相加
// 如果是运算符表达式,则递归调用
public int interpreter(HashMap inputMap) {
return super.left.interpreter(inputMap) + super.right.interpreter(inputMap);
}
}
// 非终结符表达式具体实现-减法表达式
class SubExpression extends SymbolExpression {
public SubExpression(Expression left, Expression right) {
super(left, right);
}
public int interpreter(HashMap inputMap) {
return super.left.interpreter(inputMap) - super.right.interpreter(inputMap);
}
}
// 环境角色-计算器
class Calculator {
// 计算器要进行计算的表达式
private Expression expression;
// 解析传入的字符串表达式,构造计算器要进行计算的表达式
// 例如:expStr = a+b-c
public Calculator(String expStr) {
// 用栈来存取一个临时的计算器表达式
Stack stack = new Stack();
// 将字符串表达式拆分成字符数组
char[] charArray = expStr.toCharArray();
// 用于存放临时的左右表达式
Expression left = null;
Expression right = null;
// 遍历字符数组,根据不同的情况做不同的处理
for (int i = 0; i < charArray.length; i++) {
switch (charArray[i]) {
case '+':
// 从栈中获取临时的计算器表达式,赋值给临时的左表达式
left = stack.pop();
// 运算符后面的空字符则直接跳过
while (String.valueOf(charArray[++i]) == " ") {
}
// 将运算符后面的变量,构造成值表达式,然后赋值给临时的右表达式
right = new VarExpression(String.valueOf(charArray[i]));
// 根据左右表达式构造出加法表达式,作为临时的计算器表达式传入栈中
stack.push(new AddExpression(left, right));
break;
case '-':
left = stack.pop();
while (String.valueOf(charArray[++i]) == " ") {
}
right = new VarExpression(String.valueOf(charArray[i]));
stack.push(new SubExpression(left, right));
break;
case ' ':
break;
default:
// 剩余的就是变量,构造成值表达式,作为临时的计算器表达式传入栈中
stack.push(new VarExpression(String.valueOf(charArray[i])));
break;
}
}
// 当遍历完整个charArray数组后,从栈中获取计算器表达式
this.expression = stack.pop();
}
public int run(HashMap inputMap) {
// 将用户输入的表达式的值HashMap,传入给计算器表达式进行计算
return this.expression.interpreter(inputMap);
}
}
运行程序,结果如下:
请输入表达式:a + b - c
请输入a的值:10
请输入b的值:30
请输入c的值:20
运算结果:a + b - c = 20