解释器模式
前言
- 是一种不常用的设计模式,用于描述如何构成一个简单的语言解释器,主要用于使用面向对象语言开发的编译器和解释器设计。
- 当我们需要开发一种新的语言时,可以考虑使用解释器模式。
但是,尽量不要使用解释器模式,后期维护会有很大麻烦。在项目中,可以使用Jruby,Groovy、java的js引擎来替代解释器的作用,弥补java语言的不足。
一、具体实现
以四则运算来举例子,实现对计算表达式的解释。
1.抽象解释器
package interpreter;
import java.util.HashMap;
public abstract class Expression {
//解析公式和数值,其中var中的key值是公式中的参数,value值是具体的数值
public abstract int interpreter(HashMap<String,Integer> var);
}
2.变量解析器
package interpreter;
import java.util.HashMap;
public class VarExpression extends Expression {
private String key;
public VarExpression(String key) {
this.key = key;
}
@Override
public int interpreter(HashMap<String, Integer> var) {
return var.get(this.key);
}
}
3.符号解析器
package interpreter;
public abstract class SymbolExpression extends Expression{
protected Expression left;
protected Expression right;
//所有的解析公式都应只关心自己左右两个表达式的结果
public SymbolExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
}
4.加法解析器
package interpreter;
import java.util.HashMap;
public class AddExpression extends SymbolExpression {
public AddExpression(Expression left, Expression right) {
super(left, right);
}
//左右两边相加
@Override
public int interpreter(HashMap<String, Integer> var) {
return super.left.interpreter(var)+super.right.interpreter(var);
}
}
5.减法解析器
package interpreter;
import java.util.HashMap;
public class SubExpression extends SymbolExpression {
public SubExpression(Expression left, Expression right) {
super(left, right);
}
//左右两边相减
@Override
public int interpreter(HashMap<String, Integer> var) {
return super.left.interpreter(var)-super.right.interpreter(var);
}
}
6.封装计算器
package interpreter;
import java.util.HashMap;
import java.util.Stack;
public class Calculator {
//定义表达式
private Expression expression;
//构造函数传参,并解析
public Calculator(String expStr){
//定义一个堆栈,安排运算顺序
Stack<Expression> 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();
right = new VarExpression(String.valueOf(charArray[++i]));
stack.push(new AddExpression(left,right));
break;
//减法
case '-':
left = stack.pop();
right = new VarExpression(String.valueOf(charArray[++i]));
stack.push(new SubExpression(left,right));
break;
//其他
default:
stack.push(new VarExpression(String.valueOf(charArray[i])));
}
}
//把计算结果抛出
this.expression = stack.pop();
}
//开始运算
public int run(HashMap<String,Integer> var){
return this.expression.interpreter(var);
}
}
7.测试类
package interpreter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
public class Client {
public static void main(String[] args) throws IOException {
String expStr = getExpStr();
//赋值
HashMap<String , Integer> var = getValue(expStr);
Calculator cal = new Calculator(expStr);
System.out.println("运算结果是:"+expStr+"="+cal.run(var));
}
//获得表达式
public static String getExpStr() throws IOException {
System.out.println("请输入表达式:");
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 c : expStr.toCharArray()) {
if(c != '+' && c != '-'){
//解决重复参数问题
if(!map.containsKey(String.valueOf(c))){
System.out.println("请输入"+c+"的值:");
String in = (new BufferedReader(
new InputStreamReader(System.in)
)).readLine();
map.put(String.valueOf(c),Integer.valueOf(in));
}
}
}
return map;
}
}
结果:
二、应用场景
- EL表达式式的处理
- 正则表达式解释器
- SQL语法的解释器
- 数学表达式解析器
- 如现成的工具包:Math Expression String Parser、Expression4J等。
– MESP的网址: http://sourceforge.net/projects/expression-tree/
– Expression4J的网址: http://sourceforge.net/projects/expression4j
总结
- 优点: 易于改变和扩展方法、易于实现文法定义
- 缺点:复杂的文法难以维护
- 使用场景:
1.重复发生的问题可以使用解释器模式
2.一个简单语法需要解释的场景
3.在某些商业环境下也会采用解释器模式