共计 4387 个字符,预计需要花费 11 分钟才能阅读完成。
问题引入
四则运算问题
通过解释器模式来实现四则运算,如计算 a+b-c 的值,具体要求 1) 先输出表达式的模式,比方 a+b+c-d+e, 要求表达式的字母不能反复 2) 在别离输出 a ,b, c, d, e 的值 3) 最初求出后果:如图
传统计划解决四则运算问题剖析
- 编写一个办法,接管表达式的模式,而后依据用户输出的数值进行解析,失去后果
- 问题剖析:如果退出新的运算符,比方 * / (等等,不利于扩大,另外让一个办法来 解析会造成程序结构凌乱,不够清晰 .
- 解决方案:能够思考应用解释器模式,即:表达式 -> 解释器 (能够有多种) -> 结 果
解释器模式
根本介绍
- 在编译原理中,一个算术表达式通过 词法分析器 造成词法单元,而后这些词法 单元再通过 语法分析器 构建语法分析树,最终造成一颗形象的语法分析树。这 里的词法分析器和语法分析器都能够看做是解释器
- 解释器模式(Interpreter Pattern):是指给定一个语言 (表达式),定义它的文法 的一种示意,并定义一个解释器,应用该解释器来解释语言中的句子 (表达式)
- 利用场景 • 利用能够将一个须要解释执行的语言中的句子示意为一个形象语法树 • 一些反复呈现的问题能够用一种简略的语言来表白 • 一个简略语法须要解释的场景
- 这样的例子还有,比方编译器、运算表达式计算、正则表达式、机器人等
原理类图
对原理类图的阐明 - 即 (解释器模式的角色及职责)
- Context: 是环境角色, 含有解释器之外的全局信息.
- AbstractExpression: 形象表达式,申明一个形象的解释操作, 这个办法为形象语法树中所有的节点所 共享
- TerminalExpression: 为终结符表达式, 实现与文法中的终结符相干的解释操作
- NonTermialExpression: 为非终结符表达式,为文法中的非终结符实现解释操作.
- 阐明:输出 Context he TerminalExpression 信息通过 Client 输出即可
代码实现
形象表达式
/**
- 抽象类表达式,通过 HashMap 键值对, 能够获取到变量的值
- @author Administrator
*/ public abstract class Expression {// a + b – c // 解释公式和数值, key 就是公式 ( 表达式) 参数 [a,b,c], value 就是就是具体值 // HashMap {a=10, b=20} public abstract int interpreter(HashMap<String, Integer> var); }
形象运算合乎
/**
- 形象运算符号解析器 这里,每个运算符号,都只和本人左右两个数字有关系,
- 但左右两个数字有可能也是一个解析的后果,无论何种类型,都是 Expression 类的实现类
- @author Administrator
*/ public class SymbolExpression extends Expression {
protected Expression left; protected Expression right;
public SymbolExpression(Expression left, Expression right) {this.left = left; this.right = right;}
// 因为 SymbolExpression 是让其子类来实现,因而 interpreter 是一个默认实现 @Override public int interpreter(HashMap<String, Integer> var) {// TODO Auto-generated method stub return 0;} }
加法
/**
- 加法解释器
- @author Administrator
*/ public class AddExpression extends SymbolExpression {
public AddExpression(Expression left, Expression right) {super(left, right); }
// 解决相加 //var 依然是 {a=10,b=20}… // 一会咱们 debug 源码, 就 ok public int interpreter(HashMap<String, Integer> var) {//super.left.interpreter(var):返回 left 表达式对应的值 a = 10 //super.right.interpreter(var): 返回 right 表达式对应值 b = 20 return super.left.interpreter(var) + super.right.interpreter(var); } }
减法
public class SubExpression extends SymbolExpression {
public SubExpression(Expression left, Expression right) {super(left, right); }
// 求出 left 和 right 表达式相减后的后果 public int interpreter(HashMap<String, Integer> var) {return super.left.interpreter(var) – super.right.interpreter(var); } }
变量解释器
/**
- 变量的解释器
- @author Administrator
*/ public class VarExpression extends Expression {
private String key; // key=a,key=b,key=c
public VarExpression(String key) {this.key = key;}
// var 就是 {a=10, b=20} // interpreter 依据 变量名称,返回对应值 @Override public int interpreter(HashMap<String, Integer> var) {return var.get(this.key); } }
计算器
public class Calculator {
// 定义表达式 private Expression expression;
// 构造函数传参,并解析 public Calculator(String expStr) {// expStr = a+b // 安顿运算先后顺序 Stack stack = new Stack<>(); // 表达式拆分成字符数组 char[] charArray = expStr.toCharArray();// [a, +, b]
Expression left = null;
Expression right = null;
// 遍历咱们的字符数组,即遍历 [a, +, b]
// 针对不同的状况,做解决
for (int i = 0; i < charArray.length; i++) {
switch (charArray[i]) {
case ‘+’: //
left = stack.pop();// 从 stack 取出 left => “a”
right = new VarExpression(String.valueOf(charArray[++i]));// 取出右表达式 “b”
stack.push(new AddExpression(left, right));// 而后依据失去 left 和 right 构建 AddExpresson 退出 stack
break;
case ‘-‘: //
left = stack.pop();
right = new VarExpression(String.valueOf(charArray[++i]));
stack.push(new SubExpression(left, right));
break;
default:
// 如果是一个 Var 就创立要给 VarExpression 对象,并 push 到 stack
stack.push(new VarExpression(String.valueOf(charArray[i])));
break;
}
}
// 当遍历残缺个 charArray 数组后,stack 就失去最初 Expression
this.expression = stack.pop();
}
public int run(HashMap<String, Integer> var) {// 最初将表达式 a + b 和 var = {a=10,b=20} // 而后传递给 expression 的 interpreter 进行解释执行 return this.expression.interpreter(var); } }
客户端
public class ClientTest {
public static void main(String[] args) throws IOException {// TODO Auto-generated method stub String expStr = getExpStr(); // a+b HashMap<String, Integer> var = getValue(expStr);// var {a=10, b=20} Calculator calculator = new Calculator(expStr); System.out.println(“运算后果:”+ expStr +“=”+ calculator.run(var)); }
// 取得表达式 public static String getExpStr() throws IOException { System.out.print(“请输出表达式:”); return (new BufferedReader(new InputStreamReader(System.in))).readLine();}
// 取得值映射 public static HashMap<String, Integer> getValue(String expStr) throws IOException {HashMap<String, Integer> map = new HashMap<>();
for (char ch : expStr.toCharArray()) {
if (ch != ‘+’ && ch != ‘-‘) {
if (!map.containsKey(String.valueOf(ch))) {
System.out.print(“ 请输出 ” + String.valueOf(ch) + “ 的值:”);
String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
map.put(String.valueOf(ch), Integer.valueOf(in));
}
}
}
return map;
} }
注意事项和细节
- 当有一个语言须要解释执行,可将该语言中的句子示意为一个形象语法树,就能够 思考应用解释器模式,让程序具备良好的扩展性
- 利用场景:编译器、运算表达式计算、正则表达式、机器人等
- 应用解释器可能带来的问题:解释器模式会引起类收缩、解释器模式采纳递归调用 办法,将会导致调试非常复杂、效率可能升高 .