设计模式读书笔记之解释器模式(Interpreter pattern)

来源:互联网 发布:高洛峰php视频教程 编辑:程序博客网 时间:2024/06/03 21:35

解释器模式:给定一个语言, 定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
由定义来看,解释器模式就是一个不常用的模式,但是学习一下也没有坏处.
我第一次听到解释器模式的时候想到的东西就是命令行(CMD)解释器,这就是典型的望文生义.但是解释器模式也没有想象中的复杂, 先举两个例子来对解释器模式建立一个大体的印象.第一个是: 早期的手机中都有一个铃声编辑器, 你可以自己输入1 2 3 4 5 6 7 等来编辑一个铃声,手机中一定有一个程序来读取你编辑的文件,然后按照一定的发音规则来播放它们. 那么这个播放程序就是一个解释器, 输入的乐谱就是就是音乐的文法表示. 另一个例子: 银行经常要用复杂而变化的模型来计算数据, 比如(1+r)^n*c, (r=Rate, n=Years, c=Capital)这个公示就是计算一笔存款存n年之后的的总额.如果说这个公式比较固定不变, 那么我们写一个函数/方法就搞定了, 但是如果随着银行产品种类的增多, 业务种类的增多, 公式将会多种多样,已经不再可能用函数来应对需求的变化,于是可以有一个公式编辑器,程序通过解析公式,然后给公式的参数赋值就可以应对需求. 那么这个程序就是一个解释器.
以一个简单的模型公式为例实现一个解释器. (这个例子也是我在网上看到一个网友秦小波给出的, 我觉得非常好. 他后来把23种设计模式的读书笔记写成一本书, 而且已经出版了, 书名我不说,以免有做广告之嫌,大家可以看这个链接,http://www.javaeye.com/topic/372233, 里面有pdf文档) . 要求指定参与运算的元素(如a,b,c),然后输入公式即可计算出结果. 为了演示的方便,只考虑加减法.

如果一个系统中参与运算的元素为a,b,c,d ... 当然这些元素背后对应的物理意义或者业务意义我们就不细追究. 客户端指定一个公式,如 a+b-c, a+b+c-d, 就可以计算出结果.

 先看一个类图:

VarExpression用来解析运算元素, 如a,b,c, VarExpression的工作比较简单, 它只需要简单的获得元素的值即可, SybmolExpression用来解析运算符, 它有两个子类分别解析加法符号和减法符号, AddExpression, SubExpression. SybmolExpression要稍微复杂一点, SybmolExpression要先获得操作符左面的值和右面的值,然后才能获得结果. 我们需要增加一个封装类来处理进行封装,定义为Calculator.

[java] view plain copy
  1. package designpattern.intpreter;  
  2. import <a href="http://lib.csdn.net/base/17" class='replace_word' title="Java EE知识库" target='_blank' style='color:#df3434; font-weight:bold;'>Java</a>.util.HashMap;  
  3.   
  4. public interface Expression {  
  5.     public int interprete(HashMap<String,Integer> var);  
  6. }  
  7. //////////////////////////  
  8. package designpattern.intpreter;  
  9.   
  10. import java.util.HashMap;  
  11.   
  12. public class VarExpression implements Expression{  
  13.     private String key;  
  14.     public VarExpression(String key){  
  15.         this.key = key;  
  16.     }  
  17.       
  18.     public int interprete(HashMap<String,Integer> var) {  
  19.         return (Integer)var.get(this.key);  
  20.     }  
  21. }  
  22. ////////////////////////////  
  23. package designpattern.intpreter;  
  24.   
  25. public abstract class SymbolExpression implements Expression {  
  26.     protected Expression left;  
  27.     protected Expression right;  
  28.   
  29.     // 所有的解析公式都应只关心自己左右两个表达式的结果  
  30.     public SymbolExpression(Expression left, Expression right) {  
  31.         this.left = left;  
  32.         this.right = right;  
  33.     }  
  34. }  
  35. //////////////////////////////////  
  36. package designpattern.intpreter;  
  37.   
  38. import java.util.HashMap;  
  39.   
  40. public class AddExpression extends SymbolExpression {  
  41.     public AddExpression(Expression _left, Expression _right) {  
  42.         super(_left, _right);  
  43.     }  
  44.   
  45.     // 把左右两个表达式运算的结果加起来  
  46.     public int interprete(HashMap<String, Integer> var) {  
  47.         return super.left.interprete(var) + super.right.interprete(var);  
  48.     }  
  49. }  
  50. ///////////////////////////////////  
  51. package designpattern.intpreter;  
  52.   
  53. import java.util.HashMap;  
  54.   
  55. public class SubExpression extends SymbolExpression {  
  56.     public SubExpression(Expression _left, Expression _right) {  
  57.         super(_left, _right);  
  58.     }  
  59.   
  60.     // 左右两个表达式相减  
  61.     public int interprete(HashMap<String, Integer> var) {  
  62.         return super.left.interprete(var) - super.right.interprete(var);  
  63.     }  
  64.   
  65. }  
  66. ////////////////////////////  
  67. package designpattern.intpreter;  
  68. import java.util.HashMap;  
  69. import java.util.Stack;  
  70.   
  71. public class Calculator {  
  72.     private Expression expression;  
  73.     public Calculator(String expStr) {  
  74.         // 定义一个堆栈,安排运算的先后顺序  
  75.         Stack<Expression> stack = new Stack<Expression>();  
  76.         // 表达式拆分为字符数组  
  77.         char[] charArray = expStr.toCharArray();  
  78.         // 运算  
  79.         Expression left = null;  
  80.         Expression right = null;  
  81.         for (int i = 0; i < charArray.length; i++) {  
  82.             switch (charArray[i]) {  
  83.             case '+'// 加法  
  84.                 // 加法结果放到堆栈中  
  85.                 left = stack.pop();  
  86.                 right = new VarExpression(String.valueOf(charArray[++i]));  
  87.                 stack.push(new AddExpression(left, right));  
  88.                 break;  
  89.             case '-':  
  90.                 left = stack.pop();  
  91.                 right = new VarExpression(String.valueOf(charArray[++i]));  
  92.                 stack.push(new SubExpression(left, right));  
  93.                 break;  
  94.             default// 公式中的变量  
  95.                 stack.push(new VarExpression(String.valueOf(charArray[i])));  
  96.             }  
  97.         }  
  98.         // 把运算结果抛出来  
  99.         this.expression = stack.pop();  
  100.     }  
  101.   
  102.     // 开始运算  
  103.     public int run(HashMap<String, Integer> var) {  
  104.         return this.expression.interprete(var);  
  105.     }  
  106. }  
  107. //////////////////////////////  
  108. //测试用例  
  109. package designpattern.intpreter;  
  110. import java.util.HashMap;  
  111.   
  112. public class Client {  
  113.     public static void main(String[] args){  
  114.         //构造运算元素的值列表  
  115.         HashMap<String, Integer> ctx = new HashMap<String, Integer>();  
  116.         ctx.put("a"10);  
  117.         ctx.put("b"20);  
  118.         ctx.put("c"30);  
  119.         ctx.put("d"40);  
  120.         ctx.put("e"50);  
  121.         ctx.put("f"60);  
  122.         Calculator calc = new Calculator("a+b-c");  
  123.         int result = calc.run(ctx);  
  124.         System.out.println("Result of a+b-c: " + result);  
  125.         calc = new Calculator("d-a-b+c");  
  126.         result = calc.run(ctx);  
  127.         System.out.println("Result of d-a-b+c: " + result);  
  128.     }  
  129. }  

通过这里例子, 再回头看解释器模式的定义: 给定一种语言, 本例中就是一个简单的加减运算. 定义一种文法表示, 本例中就是指定的参与运算的元素(abcdef)以及运算符(+-),以及由它们构造而成的公式. 给定一个解释器来解释语言中的句子: 本例中的解释器是多个类的组合,包括Calculator和Expression.

最后给出解释器模式的uml类图, 虽然我觉得这个图没有传达出多少有用的信息.

图中TerminalExpression表示终结符表达式, 实现与文法中的元素相关联的解释操作, 本例中相当于VarExpression. 图中NonterminalExpression是非终结符表达式, 实现与规则相关的文法,如本例中的加法, 减法.

 

经典例子:

JDK中的SimpleDateFormat, 根据你给定的规则(如mm/dd/yyyy, yyyy年MM月dd日),把一个字符串翻译成一个日期

0 0