一、解释器模式
1、定义
解释器模式(Interpreter Pattern)
指给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子,属于行为型设计模式。
解释器模式是一种按照规定的文法(语法)进行解析的模式。其核心思想就是识别文法,构建解释。
2、结构
(1)模式的结构
主要角色如下:
- 抽象表达式(IExpression):负责定义一个解释方法 interpret,交由具体子类进行具体解释。
- 终结符表达式(TerminalExpression):实现文法中与终结符有关的解释操作。通常一个解释器中只有- 一个终结符表达式,但有多个实例,对应不同的终结符。
- 非终结符表达式(NonterminalExpression):实现文法中与非终结符有关的解释操作。
- 上下文环境类(Context):包含解释器之外的全局信息。它一般用来存放文法中各个终结符所对应的具体值。
3、优缺点
优点:
- 由于语法由很多类表示,所以,当语法规则或者扩展语法时,只需要修改或者扩展表达式即可。
- 对于简单的文法应当比较简单且易于实现,过于复杂的语法并不适合解释器模式。
缺点:
- 由于语法由很多类表示,过于复杂时,会产生大量的解释类,引起类臃肿,增加系统维护的难度。
- 解释器模式采用递归调用方法,当完整表达式层级较深时,解释效率会下降。
4、使用场景
- 一些重复出现的问题可以用一种简单的语言进行表达。
- 一个简单语法需要解释的场景。
5、在框架源码中使用
- JDK源码中的 Pattern对正则表达式的编译和解析。
- Spring源码中的 ExpressionParser接口。
二、模式的应用实例
使用解释器模式来简单的实现一个计算器,这里不考虑运算符计算顺序。
(1)抽象表达式
interface IArithmeticInterpreter {
int interpret();
}
// 数字表达式
class NumberInterpreter implements IArithmeticInterpreter {
private int value;
public NumberInterpreter(int value) {
this.value = value;
}
@Override
public int interpret() {
return this.value;
}
}
(2)终结符表达式
abstract class Interpreter implements IArithmeticInterpreter {
protected IArithmeticInterpreter left;
protected IArithmeticInterpreter right;
public Interpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
this.left = left;
this.right = right;
}
}
(3)非终结符表达式
class AddInterpreter extends Interpreter {
public AddInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
super(left, right);
}
@Override
public int interpret() {
return this.left.interpret() + this.right.interpret();
}
}
class SubInterpreter extends Interpreter {
public SubInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
super(left, right);
}
@Override
public int interpret() {
return this.left.interpret() - this.right.interpret();
}
}
class MultiInterpreter extends Interpreter {
public MultiInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
super(left, right);
}
@Override
public int interpret() {
return this.left.interpret() * this.right.interpret();
}
}
class DivInterpreter extends Interpreter {
public DivInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
super(left, right);
}
@Override
public int interpret() {
return this.left.interpret() / this.right.interpret();
}
}
(4)上下文环境类 - 计算器
class GPCalculator {
private Stack<IArithmeticInterpreter> stack = new Stack<>();
public GPCalculator(String expression) {
this.parse(expression);
}
/**
* 解析表达式:约定表达式以空格分隔
*
* @param expression
*/
private void parse(String expression) {
String[] elements = expression.split(" ");
IArithmeticInterpreter left, right;
for (int i = 0; i < elements.length; i++) {
String operator = elements[i];
if("+".equals(operator) || "-".equals(operator) || "*".equals(operator) || "/".equals(operator)){
System.out.println("应用运算符:" + operator);
left = this.stack.pop();
right = new NumberInterpreter(Integer.valueOf(elements[++i]));
System.out.println("出栈:left=" + left.interpret() + ", right=" + right.interpret());
Interpreter interpreter = null;
if("+".equals(operator)){
interpreter = new AddInterpreter(left, right);
}else if("-".equals(operator)){
interpreter = new SubInterpreter(left, right);
}else if("*".equals(operator)){
interpreter = new MultiInterpreter(left, right);
}else if("/".equals(operator)){
interpreter = new DivInterpreter(left, right);
}else{
new RuntimeException("不支持该运算符:" + operator);
}
this.stack.push(interpreter);
System.out.println("应用运算符计算结果入栈,result=" + interpreter.interpret());
}else{
NumberInterpreter numberInterpreter = new NumberInterpreter(Integer.valueOf(elements[i]));
this.stack.push(numberInterpreter);
System.out.println("入栈:" + numberInterpreter.interpret());
}
}
}
// 获取计算结果
public int calculate() {
return this.stack.pop().interpret();
}
}
(5)测试
public static void main(String[] args) {
GPCalculator gpCalculator = new GPCalculator("2 + 3");
System.out.println("2 + 3 = "+ gpCalculator.calculate());
System.out.println("-------------");
GPCalculator gpCalculator2 = new GPCalculator("2 * 3");
System.out.println("2 * 3 = "+ gpCalculator2.calculate());
System.out.println("-------------");
GPCalculator gpCalculator3 = new GPCalculator("2 + 3 - 1");
System.out.println("2 + 3 - 1 = "+ gpCalculator3.calculate());
}
– 求知若饥,虚心若愚。