设计模式(十六)----解释器模式

概述

系统中若某一特定类型的问题频繁发生,此时就有必要将这些问题的实例表述为一个语言中的句子,因此可以构建一个解释器,然后利用该解释器来解释这些句子,以此来解决问题。

解释器模式就是定义语言的文法,并且建立一个解释器来解释该语言中的句子。

解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。

解释器模式被用于SQL解析,符号处理引擎等。

给定一个语言,并定义它的文法表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

解释器模式主要包含下面几个角色
AbstractExpression:抽象表达式。声明一个抽象的解释操作,该接口为抽象语法树中所有的节点共享。
TerminalExpression:终结符表达式。实现抽象表达式中所要求的方法。文法中每个终结符都有一个终结表达式与之相对应。
NonterminalExpression:非终结符表达式。为文法中的非终结符进行相关的解释操作。
Context:环境类。包含解释器之外的一些全局信息,一般是HashMap。
Client:客户类。

实例

用解释器模式模拟一个基本的整型数据计算器。
抽象表达式

public interface Node {
	public int interpret();
}

非终结符表达式

public class ValueNode implements Node {
	private int value;
	public ValueNode(int value) {
		this.value = value;
	}
	public int interpret() {
		return this.value;
	}
}

主要用于解释表达式中的数据。
终结符表达式抽象类

public abstract class OperatorNode implements Node {
	protected Node left;
	protected Node right;
	public OperatorNode(Node left,Node right) {
		this.left = left;
		this.right = right;
	}
}

用于解释表达式中的运算符,同时用来构建抽象语法树。
终结符表达式具体类
加法类

public class AddNode extends OperatorNode {
	public AddNode(Node left,Node right) {
		super(left,right);
	}
	public int interpret() {
		return left.interpret() + right.interpret();
	}
}

减法类

publc class Minus extends OperatorNode {
	public Minus(Node left,Node right) {
		super(left,right);
	}
	public int interpret() {
		return left.interpret() - right.interpret();
	}
}

乘法类

public class MultiplyNode extends OperatorNode {
	public Multiply(Node left,Node right) {
		super(left,right);
	}
	public int interpret() {
		return left.interpret() * right.interpret();
	}
}

除法类

public class DivideNode extends OperatorNode {
	public DivideNode(Node left,Node right) {
		super(left,right);
	}
	public int interpret() {
		return left.interpret() / right.interpret();
	}
}

计算器类(Context环境类)

public class Calculator {
	//要计算的表达式
	private String expression;
	//数据或运算符
	private Node node;

	public void build(String expression) {
		Node left = null;
		Node right = null;
		Stack stack = new Stack();

		//拆分表达式,将其中的每个字符(数据或运算符)都作为数组的一个元素
		String[] exArr = expression.split(" ");

		for(int i = 0;i < exArr.length;i++) {
			if(exArr[i].equalsIgnoreCase("+")) {//加运算符
				//将栈顶对象取出,并让left指向该对象
				left = (Node) stack.pop();
				int val = Integer.parseInt(exArr[++i]);
				right = new ValueNode(val);	
				//将加运算后得到的结果放在栈顶
				stack.push(new AddNode(left,right));
			} else if (exArr[i].equalsIgnoreCase("-")) {//减运算符
				//将栈顶对象取出,并让left指向该对象
				left = (Node) stack.pop();
				int val = Integer.parseInt(exArr[++i]);
				right = new ValueNode(val);
				//将减运算后得到的结果放在栈顶
				stack.push(new MinusNode(left,right));
			} else if (exArr[i].equalsIgnoreCase("*")) {//乘运算符
				//将栈顶对象取出,并让left指向该对象
				left = (Node) stack.pop();
				int val = Integer.parseInt(exArr[++i]);
				right = new ValueNode(val);
				//将乘运算后得到的结果放在栈顶
				stack.push(new Multiply(left,right));
			} else if (exArr[i].equalsIgnoreCase("/")) {//除运算符
				//将栈顶对象取出,并让left指向该对象
				left = (Node) stack.pop();
				int val = Integer.parseInt(exArr[++i]);
				right = new ValueNode(val);
				//将除运算后得到的结果放在栈顶
				stack.push(new Divide(left,right));
			} else {//数据
				stack.push(new ValueNode(Integer.parseInt(exArr[i])));
			}
		}
		this.node = (Node)stack.pop();
	}
	//获取结果
	public int compute() {
		return node.interpret();
	}
}

客户端测试类

public class InterpreterPatternDemo {
	public static void main(String[] args) {
		//要计算的表达式
		String expression = "3 * 6 / 2 + 5 - 3";
		Calculator calculator = new Calculator();
		calculator.build(expression);
		//结果
		int result = calculator.compute();
		System.out.println("表达式结果为:" + result);
	}
}

打印结果
在这里插入图片描述

总结

优点:扩展性较好,比较灵活;增加新的解释表达式的方式;易于实现文法。
缺点:执行效率较低,可利用场景较少;对于复杂的文法比较难以维护;容易引起类的膨胀;采用递归调用方法。

使用场景:可将一个需要解释执行的语言中的句子表示为一个抽象语法树;一些重复出现的问题可用一种简单的语言来进行表达;一个简单语法需要解释的场景。
注:解释器模式可利用场景比较少,在Java中若碰到可使用expression4J来代替。

虽然解释器的可扩展性强,但若语法规则的数目太大的时候,该模式可能就会变得异常复杂。所以解释器模式适用于文法较为简单的。
解释器模式可处理脚本语言和编程语言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值