这篇博客我们来介绍一下解释器模式(Interpreter Pattern),也是行为型设计模式之一,是一种用的比较少的设计模式,其提供了一种解释语言的语法或表达式的方式,该模式定义了一个表达式接口,通过该接口解释一个特定的上下文。在这么多的设计模式中,解释器模式在实际运用上相对来说要少很多,因为我们很少会去构造一个语言的文法。虽然你几乎用不到这个模式,但是看一看还是能受到一定的启发的。
  转载请注明出处:http://blog.csdn.net/self_study/article/details/52737559。
  PS:对技术感兴趣的同鞋加群544645972一起交流。

设计模式总目录

  java/android 设计模式学习笔记目录

特点

  给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
  该模式的使用场景相当广泛,总的概括下来大概有以下几种:

  • 专用的数据库查询语言,比如 SQL;
  • 通常用来解释通信协议的专用计算机语言;
  • 如果某个简单的语言需要解释执行而且可以将语言中的语句表示为一个抽象语法树时可以考虑使用解释器模式。

UML类图

  我们来看看解释器模式的 uml 类图:
  
这个模式有几个角色:

  • AbstractExpression:抽象表达式
  • 声明一个抽象的解释操作父类,并定义一个抽象的 interpret() 解释方法,其具体的实现在各个具体的子类解释器中完成。
  • TerminalExpression:终结符表达式
  • 实现了抽象表达式角色所要求的接口,主要是一个interpret()方法;文法中的每一个终结符都有一个具体终结表达式与之相对应。比如有一个简单的公式R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。
  • NonterminalExpression:非终结符表达式
  • 文法中的每一条规则都需要一个具体的非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,“+”就是非终结符,解析“+”的解释器就是一个非终结符表达式。
  • Context:上下文环境类
  • 这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了。
  • Client:客户类
  • 解析表达式,构建抽象语法树,执行具体的解释操作等。
  通用代码如下:

public abstract class AbstractExpression {    /**     * 抽象的解析方法     * @param context 上下文环境对象     */    public abstract void interpret(Context context);}public class TerminalExpression extends AbstractExpression{    @Override    public void interpret(Context context) {        //实现文法中与终结符有关的解释操作    }}public class NonterminalExpression extends AbstractExpression{    @Override    public void interpret(Context context) {        //实现文法中与非终结符有关的解释操作    }}public class Context {}public class Client {    public static void main(String[] args) {        //根据文法对特定句子构建抽象语法树后解释    }}

示例与源码

  为了说明解释器模式的实现办法,这里就以 wiki 上的算术表达式的解释为例,如表达式“m + n + p”,如果我们使用解释器模式对该表达式进行解释,那么代表数字的 m、n 和 p 三个字母我们就可以看成是终结符号,而“+”这个算术运算符号则可当作非终结符号。这个简单的文法如下:

expression ::= plus | minus | variable | numberplus       ::= expression expression '+'minus      ::= expression expression '-'variable   ::= 'a' | 'b' | 'c' | ... | 'z'digit      ::= '0' | '1' | ... | '9'number     ::= digit | digit number

定义一个包含逆波兰表达式的语言:

a b +a b c + -a b + c a - -

于是根据上面的语言和文法,我们可以简单写出下面的示例:
AbstractExpression,TerminalExpression,NonterminalExpression

import java.util.Map;interface Expression {    public int interpret(Map variables);}class Number implements Expression {    private int number;    public Number(int number)       { this.number = number; }    public int interpret(Map variables)  { return number; }}class Plus implements Expression {    Expression leftOperand;    Expression rightOperand;    public Plus(Expression left, Expression right) {         leftOperand = left;         rightOperand = right;    }    public int interpret(Map variables)  {         return leftOperand.interpret(variables) + rightOperand.interpret(variables);    }}class Minus implements Expression {    Expression leftOperand;    Expression rightOperand;    public Minus(Expression left, Expression right) {         leftOperand = left;         rightOperand = right;    }    public int interpret(Map variables)  {         return leftOperand.interpret(variables) - rightOperand.interpret(variables);    }}class Variable implements Expression {    private String name;    public Variable(String name)       { this.name = name; }    public int interpret(Map variables)  {         if(null==variables.get(name)) return 0; //Either return new Number(0).        return variables.get(name).interpret(variables);     }}

Context

import java.util.Map;import java.util.Stack;class Evaluator {    private Expression syntaxTree;    public Evaluator(String expression) {        Stack<Expression> expressionStack = new Stack<Expression>();        for (String token : expression.split(" ")) {            if  (token.equals("+")) {                Expression subExpression = new Plus(expressionStack.pop(), expressionStack.pop());                expressionStack.push( subExpression );            }            else if (token.equals("-")) {                // it's necessary remove first the right operand from the stack                Expression right = expressionStack.pop();                // ..and after the left one                Expression left = expressionStack.pop();                Expression subExpression = new Minus(left, right);                expressionStack.push( subExpression );            }            else                                        expressionStack.push( new Variable(token) );        }        syntaxTree = expressionStack.pop();    }    public int calculate(Map<String,Expression> context) {        return syntaxTree.interpret(context);    }}

Client

import java.util.Map;import java.util.HashMap;public class InterpreterExample {    public static void main(String[] args) {        String expression = "w x z - +";        Evaluator sentence = new Evaluator(expression);        Map variables = new HashMap();        variables.put("w", new Number(5));        variables.put("x", new Number(10));        variables.put("z", new Number(42));        int result = sentence.calculate(variables);        System.out.println(result);    }}

总结

  解释器模式的优点是其灵活的扩展性,当我们想对文法规则进行扩展延伸时,只需要增加相应的非终结符解释器,并在构建抽象语法树时,使用到新增的解释器对象进行具体的解释即可,非常方便。
  解释器模式的缺点也显而易见,因为对于每一条文法都可以对应至少一个解释器,其会生成大量的类,导致后期维护困难;同时,对于过于复杂的文法,构建其抽象语法树会显得异常繁琐,甚至有可能会出现需要构建多棵抽象语法树的情况,因此,对于复杂的文法并不推荐使用解释器模式。

源码下载

  https://github.com/zhaozepeng/Design-Patterns/tree/master/InterpreterPattern

引用

https://en.wikipedia.org/wiki/Interpreter_pattern
http://www.cnblogs.com/java-my-life/archive/2012/06/19/2552617.html
http://blog.csdn.net/ylchou/article/details/7594135
http://blog.csdn.net/chenhuade85/article/details/8147003

更多相关文章

  1. Android(安卓)studio 下出现"Cannot resolve symbol R"的解决方
  2. CSDN日报190718:史上最全的Android面试题集锦
  3. Android新的网络请求框架volley源码解释及示例
  4. 谷歌前实习生解释 Android不如苹果iOS原因
  5. 实用正则表达式扫描android SDcard的文件
  6. Android权限 (代码区2)
  7. Android(安卓)FragmentPagerAdapter和FragmentStatePagerAdapter
  8. Android(安卓)Weekly Notes Issue #251
  9. Android如何获取SDCard 内存

随机推荐

  1. android通过chmod命令实现文件权限修改
  2. 多核软件设计:Android(安卓)& Linux multi
  3. android与HTML5相结合实现的省市县三级联
  4. 2014-7-23 Android ImageViwe自适应屏幕
  5. 运行Android程序时,出现提示:No compatibl
  6. Android NDK带来了什么
  7. android内核编译方法[转贴]
  8. Android 程序员指南 PDF下载
  9. android 应用自身检测版本并下载
  10. android应用 小试牛刀 开发自己的应用程