一、背景
相信大家都知道四则运算,在金融行业,大大小小的模型都涉及比较复杂的运算,而且模型的不同使用的公式就不同,不同的公式需要的参数不同,所以我们不可能为每一个公式去写一个方法,或者定义一个类,那样的话会有无穷无尽的修改,添加,后期维护非常困难。解释器模式正好可以解决这样的问题。
二、概念
解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
三、代码实例
package interpreterPattern;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Stack;
/**
* 解释器模式 所谓解释器模式,就是对输入进行解释,类似正则表达式。 以加减法为例
*/
public class InterpreterPatternDemo {
// 运行四则运算
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.print("请输入表达式:");
return (new BufferedReader(new InputStreamReader(System.in)))
.readLine();
}
// 获得值映射
public static HashMap<String, Integer> getValue(String exprStr)
throws IOException {
HashMap<String, Integer> map = new HashMap<String, Integer>();
// 解析有几个参数要传递
for (char ch : exprStr.toCharArray()) {
if (ch != '+' && ch != '-') {
if (!map.containsKey(String.valueOf(ch))) { // 解决重复参数的问题
System.out.print("请输入" + ch + "的值:");
String in = (new BufferedReader(new InputStreamReader(
System.in))).readLine();
map.put(String.valueOf(ch), Integer.valueOf(in));
}
}
}
return map;
}
}
/**
* 解释器接口
*/
abstract class Expression {
// 解析公式和数值,其中var中的key值是是公式中的参数,value值是具体的数字
public abstract int interpreter(HashMap<String, Integer> var);
}
/**
* 变量解析器
*
*/
class VarExpression extends Expression {
private String key;
public VarExpression(String _key) {
this.key = _key;
}
// 从map中取之
public int interpreter(HashMap<String, Integer> var) {
return var.get(this.key);
}
}
/**
* 运算符号解析器
*
*/
abstract class SymbolExpression extends Expression {
protected Expression left;
protected Expression right;
// 所有的解析公式都应只关心自己左右两个表达式的结果
public SymbolExpression(Expression _left, Expression _right) {
this.left = _left;
this.right = _right;
}
}
/**
* 加法解析器
*
*/
class AddExpression extends SymbolExpression {
public AddExpression(Expression _left, Expression _right) {
super(_left, _right);
}
// 把左右两个表达式运算的结果加起来
public int interpreter(HashMap<String, Integer> var) {
return super.left.interpreter(var) + super.right.interpreter(var);
}
}
/**
* 减法解析器
*
*/
class SubExpression extends SymbolExpression {
public SubExpression(Expression _left, Expression _right) {
super(_left, _right);
}
// 左右两个表达式相减
public int interpreter(HashMap<String, Integer> var) {
return super.left.interpreter(var) - super.right.interpreter(var);
}
}
/**
* 运算器
*
*/
class Calculator {
// 定义的表达式
private Expression expression;
// 构造函数传参,并解析
public Calculator(String expStr) {
// 定义一个堆栈,安排运算的先后顺序
Stack<Expression> stack = new Stack<Expression>();
// 表达式拆分为字符数组
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);
}
}
四、总结
1.一些重复发生的问题可以使用解释器模式,比如不同公式重复使用不同的参数等。
2.一般情况下很少用到解释器模式,一些已有的工具可以很好地帮助解决类似的问题,比如JRuby、Groovy等。不用自己去写一个解释器。比较繁杂还容易出错。