设计模式-解释器模式
解释器模式(InterPreter Pattern)
解释器模式是指给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用 该表示 来解释语言中的句子,并按照规定的语法进行解析的模式,属于行为型模式。
比如编译器可以将源码编译为机器码,让CPU能进行识别并运行。解释器模式的作用其实与编译器一样,都是对固定的文法进行解释,构建出一个解释句子的解释器。
解释器模式实际开发中使用较少,一般源码中会使用,比如Spring的el表达式,以及jdk对正则的支持等
适用场景
- 一些重复出现的问题可以用一种简单的语言来进行表达
- 一个简单语法需要解释的场景
角色
- 抽象表达式Expression:负责定义一个解释方法interpret,交由具体子类进行具体解释
- 终结符表达式TerminalExpression:实现文法中与终结符有关的操作。文法中的每一个终结符都有一个具体终结表达式与之相呼应。比如
R=R1+R2
,R1与R2就是终结符,对应的 解析R1和R2的解释器 就是终结符表达式。通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符(R1,R2)。 - 非终结符表达式NonTerminalExpression:实现文法中与非终结符有关的解释操作。文法中的每条规则都对应于一个非终结符表达式。非终结表达式一般是文法中的运算符或者其他关键字。
- 上下文环境类Context:包含解释器之外的全局信息。他的任务一般是用来存放文法中各个终结符所对应的具体值。
代码示例
用解释器模式实现一个数学表达式计算器
- 抽象表达式角色:
package com.caozz.demo2.interpreter.calculate;
public interface IArithmeticInterpreter {
int interpret();
}
- 非终结表达式角色抽象
package com.caozz.demo2.interpreter.calculate;
public abstract class SymbolInterpreter implements IArithmeticInterpreter {
protected IArithmeticInterpreter left;
protected IArithmeticInterpreter right;
public SymbolInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
this.left = left;
this.right = right;
}
}
- 具体非终结表达式(加减乘除)
package com.caozz.demo2.interpreter.calculate;
public class AddInterpreter extends SymbolInterpreter {
public AddInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
super(left, right);
}
public int interpret() {
return this.left.interpret() + this.right.interpret();
}
}
package com.caozz.demo2.interpreter.calculate;
public class SubInterpreter extends SymbolInterpreter {
public SubInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
super(left, right);
}
public int interpret() {
return this.left.interpret() - this.right.interpret();
}
}
package com.caozz.demo2.interpreter.calculate;
public class MultiInterpreter extends SymbolInterpreter {
public MultiInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right){
super(left,right);
}
public int interpret() {
return this.left.interpret() * this.right.interpret();
}
}
package com.caozz.demo2.interpreter.calculate;
public class DivInterpreter extends SymbolInterpreter {
public DivInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right){
super(left,right);
}
public int interpret() {
return this.left.interpret() / this.right.interpret();
}
}
- 终结符表达式(数字表达式)
package com.caozz.demo2.interpreter.calculate;
public class NumInterpreter implements IArithmeticInterpreter {
private int value;
public NumInterpreter(int value) {
this.value = value;
}
public int interpret() {
return this.value;
}
}
- 计算器
parse方法对应的是不考虑优先级的,parse01是考虑优先级的
package com.caozz.demo2.interpreter.calculate;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
public class GPCalculator {
private Stack<IArithmeticInterpreter> stack = new Stack<>();
Queue<IArithmeticInterpreter> finalNum = new LinkedList<>();
public GPCalculator(String expression) {
// this.parse(expression);
this.parse01(expression);
}
private void parse(String expression) {
String [] elements = expression.split(" ");
IArithmeticInterpreter leftExpr, rightExpr;
for (int i = 0; i < elements.length ; i++) {
String operator = elements[i];
if (OperatorUtil.isOperator(operator)){
leftExpr = this.stack.pop();
rightExpr = new NumInterpreter(Integer.valueOf(elements[++i]));
System.out.println("出栈: " + leftExpr.interpret() + " 和 " + rightExpr.interpret());
this.stack.push(OperatorUtil.getInterpreter(leftExpr, rightExpr,operator));
System.out.println("应用运算符: " + operator);
}
else{
NumInterpreter numInterpreter = new NumInterpreter(Integer.valueOf(elements[i]));
this.stack.push(numInterpreter);
System.out.println("入栈: " + numInterpreter.interpret());
}
}
}
private void parse01(String expression) {
String [] elements = expression.split(" ");
Queue<String> symbols = new LinkedList<>();
Queue<String> nums = new LinkedList<>();
for (int i = 0; i < elements.length ; i++) {
String ele = elements[i];
if (OperatorUtil.isOperator(ele)){
symbols.offer(ele);
} else {
nums.offer(ele);
}
}
//先计算乘法
Stack<String> nsymbols = new Stack<>();
Stack<IArithmeticInterpreter> nnums = new Stack<>();
nnums.push(new NumInterpreter(Integer.valueOf(nums.poll())));
int symbolLen = symbols.size();
for (int j = 0; j < symbolLen; j++) {
String operator = symbols.poll();
IArithmeticInterpreter next = new NumInterpreter(Integer.valueOf(nums.poll()));
if (OperatorUtil.isAddSub(operator)) {
nsymbols.push(operator);
nnums.push(next);
} else {
IArithmeticInterpreter previous = nnums.pop();
nnums.push(new MultiInterpreter(previous,next));
}
}
//乘法计算完成后的
int len = nsymbols.size();
IArithmeticInterpreter first = nnums.pop();
finalNum.offer(first);
for (int h = 0; h < len; h++) {
String e = nsymbols.pop();
IArithmeticInterpreter pre = finalNum.poll();
IArithmeticInterpreter next = nnums.pop();
if ("+".equals(e)) {
finalNum.offer(new AddInterpreter(pre,next));
} else {
finalNum.offer(new SubInterpreter(next,pre));
}
}
}
public int calculate() {
// return this.stack.pop().interpret();
IArithmeticInterpreter poll = this.finalNum.poll();
return poll.interpret();
}
}
- 测试
package com.caozz.demo2.interpreter.calculate;
public class Test {
public static void main(String[] args) {
System.out.println("result(10 + 30): " + new GPCalculator("10 + 30").calculate());
System.out.println("result( 50 + 30 - 20 ): " + new GPCalculator("50 + 30 - 20").calculate());
System.out.println("result( 2 + 5 * 3 ): " + new GPCalculator("2 + 5 * 3").calculate());
System.out.println("result( 2 * 3 + 4 * 5 ): " + new GPCalculator("2 * 3 + 4 * 5").calculate());
System.out.println("result( 2 * 3 * 5 + 4 * 5 ): " + new GPCalculator("2 * 3 * 5 + 4 * 5").calculate());
System.out.println("result( 2 * 5 + 4 * 5 * 6 ): " + new GPCalculator("2 * 5 + 4 * 5 * 6").calculate());
//15 + 15 + 60 = 90
System.out.println("result(3 * 5 + 6 + 9 + 2 * 3 * 10): " + new GPCalculator("3 * 5 + 6 + 9 + 2 * 3 * 10").calculate());
}
}
- 测试结果
D:\software\java\jdk-17.0.2\bin\java.exe ...
result(10 + 30): 40
result( 50 + 30 - 20 ): 60
result( 2 + 5 * 3 ): 17
result( 2 * 3 + 4 * 5 ): 26
result( 2 * 3 * 5 + 4 * 5 ): 50
result( 2 * 5 + 4 * 5 * 6 ): 130
result(3 * 5 + 6 + 9 + 2 * 3 * 10): 90
Process finished with exit code 0
欢迎大家留言,以便于后面的人更快解决问题!另外亦欢迎大家可以关注我的微信公众号,方便利用零碎时间互相交流。共勉!
------愿来生只做陌上的看花人,无须入尘缘,仅行于陌上,看一川风花,无爱无伤-----