Design Patterns(十九) Interpreter
Interpreter pattern provides a way to evaluate language grammar or expression. This type of pattern comes under behavioral pattern. This pattern involves implementing an expression interface which tells to interpret a particular context. This pattern is used in SQL parsing, symbol processing engine etc.
前言 解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。
解释器模式 基本介绍:
1) 在编译原理中,一个算术表达式通过 词法分析器 形成词法单元,而后这些词法单元再通过 语法分析器 构建语法分析树,最终形成一颗抽象的语法分析树。这里的词法分析器和语法分析器都可以看做是解释器; 2) 解释器模式(Interpreter Pattern):是指给定一个语言(表达式),定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子(表达式); 3) 应用场景:1. 应用可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。2. 一些重复出现的问题可以用一种简单的语言来表达。3. 一个简单语法需要解释的场景; 4) 这样的例子还有,比如编译器、运算表达式计算、正则表达式、机器人等。
角色介绍:
1)抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。 2)终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。 3)非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。 4)环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。 5)客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。
解释器模式-UML图:
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.HashMap;import java.util.Stack;public class Interpreter { 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("运算" ); } public static String getExpStr () throws IOException { return (new BufferedReader(new InputStreamReader(System.in))).readLine(); } public static HashMap<String, Integer> getValue (String expStr) throws IOException { HashMap<String, Integer> map = new HashMap<String, Integer>(); for (char ch : expStr.toCharArray()) { if (ch != '+' && ch != '-' ) { if (!map.containsKey(String.valueOf(ch))) { String in = (new BufferedReader(new InputStreamReader(System.in))).readLine(); } } } return map; } } abstract class Expression { public abstract int interpreter (HashMap<String, Integer> var ) ; } class VarExpression extends Expression { private String key; public VarExpression (String _key) { this .key = _key; } 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(); 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) 应用场景:编译器、运算表达式计算、正则表达式、机器人等; 3) 使用解释器可能带来的问题:解释器模式会引起类膨胀、解释器模式采用递归调用方法,将会导致调试非常复杂、效率可能降低。
延伸 解释器模式 设计模式-解释器模式 解释器模式-菜鸟教程 Design Patterns - Interpreter Pattern 尚硅谷Java设计模式,韩顺平图解java设计模式
<
Design Patterns(二十) State
Design Patterns(十八) Memento
>