设计模式之解释器模式

来源:互联网 发布:windows动态桌面 编辑:程序博客网 时间:2024/06/06 03:20

设计模式之解释器模式

定义:解释器模式是一种按照规定语法进行解析的方案,给定一个语言, 定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。实际上可以理解为是一个编译器(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

优点:

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

缺点

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

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

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

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

  • 效率问题

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

 

分类: 设计模式
0 0
原创粉丝点击