码迷,mamicode.com
首页 > 其他好文 > 详细

设计模式之解释器模式

时间:2016-06-01 22:43:06      阅读:149      评论:0      收藏:0      [点我收藏+]

标签:

定义:解释器模式是一种按照规定语法进行解析的方案,给定一个语言, 定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。实际上可以理解为是一个编译器(esclipse或者vc)或者是正则表达式。

类图:

技术分享

以加减运算为例

   业务需求:输入一个模型公式(加减四则运算),然后输入模型中的参数,运算出结果。

      设计要求:

  • 公式可以运行期编辑,并且符合正常算术书写方式,例如a+b-c;
  • 高扩展性,未来增加指数、开方、极限、求导等运算符号时,较少改动量;
  • 效率可以不用考虑,晚间批量运算。

抽象表达式类

public abstract class Expression {
 
//解析公式和数值,其中var中的key值是是公式中的参数,value值是具体的数字
 
public abstract int interpreter(HashMap<String,Integer> var);
 
}

变量解析器

public 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);
 
}
 
}

加法解析器

public 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);
 
}
 
}

减法解析器

public 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);
 
}
 
}

运算器

public 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);
 
}
 
}

客户端

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.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;
 
}
 
}

  首先,要求输入公式。

请输入表达式:a+b-c

      其次,要求输入公式中的参数。

请输入a的值:100

请输入b的值:20

请输入c的值:40

      最后,运行出结果。

运算结果为:a+b-c=80

优点:

解释器是一个简单语法分析工具,它最显著的优点就是扩展性,修改语法规则只要修改相应的非终结符表达式就可以了,若扩展语法,则只要增加非终结符类就可以了。

缺点

  • 解释器模式会引起类膨胀

      每个语法都要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件,为维护带来了非常多的麻烦。

  • 解释器模式采用递归调用方法

      每个非终结符表达式只关心与自己有关的表达式,每个表达式需要知道最终的结果,必须一层一层地剥茧,无论是面向过程的语言还是面向对象的语言,递归都是在必要条件下使用的,它导致调试非常复杂。想想看,如果要排查一个语法错误,我们是不是要一个一个断点的调试下去,直到最小的语法单元。

  • 效率问题

      解释器模式由于使用了大量的循环和递归,效率是个不容忽视的问题,特别是用于解析复杂、冗长的语法时,效率是难以忍受的。

 

设计模式之解释器模式

标签:

原文地址:http://www.cnblogs.com/sker/p/5551136.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!