设计模式之解释器模式

设计模式之解释器模式

1. 什么是解释器模式

Interpreter模式也叫解释器模式,是行为模式之一,它是一种特殊的设计模式,它建立一个解释器,对于特定的计算机程序设计语言,用来解释预先定义的文法。简单地说,Interpreter模式是一种简单的语法解释器构架。

换一种解释就是定义一个语法, 定义一个解释器,该解释器处理该语法句子将某些复杂问题,表达为某种语法规则,然后构建解释器来解释处理这类句子。

解释器模式的结构:

在这里插入图片描述

  • Context:解释器上下文环境类。用来存储解释器的上下文环境,比如需要解释的文法等。

  • AbstractExpression:解释器抽象类。

  • ConcreteExpression:解释器具体实现类。

优缺点

优点:

  • 容易修改,修改语法规则只要修改相应非终结符即可

  • 扩展方便,扩展语法,只要增加非终结符类即可

缺点:

  • 对于复杂语法的表示会产生复杂的类层次结构,不便管理和维护

  • 解释器采用递归方式,效率会受影响

一般的适用场景

  • 当有一个语言需要解释执行, 并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好:

  • 该文法简单对于复杂的文法, 文法的类层次变得庞大而无法管理。此时语法分析程序生成器这样的工具是更好的选择。它们无需构建抽象语法树即可解释表达式, 这样可以节省空间而且还可能节省时间。

  • 效率不是一个关键问题,最高效的解释器通常不是通过直接解释语法分析树实现的, 而是首先将它们转换成另一种形式。例如,正则表达式通常被转换成状态机。但即使在这种情况下, 转换器仍可用解释器模式实现, 该模式仍是有用的。

使用时的注意事项:

  • 尽量不要在重要的模块中使用解释器模式

  • 解释器模式在实际的系统开发中使用的非常少

  • 可以考虑一下Expression4J、MESP、Jep等开源的解析工具包

2. 具体的实例

有一个大数据的项目,大数据统计项目遇到了问题:

按照计算模型对现有数据统计、分析、预测,一般的计算模型是一个或多个运算公式,通常是加减乘除四则运算,设计方案要有高扩展性。

计算模型的设计:

计算模型按正常算术方式书写,解释器处理语法逻辑

计算模型里有两类符号:数据和计算符

用逆波兰算法分析算式语法

用解释器模式处理数据。

这里项目中其实就是要使用解释器来计算符号公式。 解释的意思就是用一种方式或语法来执行他。

项目设计的类图如下所示:

在这里插入图片描述

具体的代码如下:

AbstractExpresstion:抽象表达式:

public abstract class AbstractExpresstion {
   public abstract Float interpreter(HashMap<String, Float> var);
}

VarExpresstion:

public class VarExpresstion extends AbstractExpresstion {
	private String key;

	public VarExpresstion(String _key) {

		this.key = _key;

	}

	@Override
	public Float interpreter(HashMap<String, Float> var) {
		// TODO Auto-generated method stub
		return var.get(this.key);
	}
}

具体的”加减乘除“运算符:


public class AddExpresstion extends SymbolExpresstion {

	public AddExpresstion(AbstractExpresstion _left, AbstractExpresstion _right) {
		super(_left, _right);
		// TODO Auto-generated constructor stub
	}

	@Override
	public Float interpreter(HashMap<String, Float> var) {
		// TODO Auto-generated method stub
		return super.left.interpreter(var) + super.right.interpreter(var);
	}
}
public class SubExpresstion extends SymbolExpresstion {

	public SubExpresstion(AbstractExpresstion _left, AbstractExpresstion _right) {
		super(_left, _right);
		// TODO Auto-generated constructor stub
	}

	@Override
	public Float interpreter(HashMap<String, Float> var) {
		// TODO Auto-generated method stub
		return super.left.interpreter(var) - super.right.interpreter(var);
	}
}

public class MultiExpresstion extends SymbolExpresstion {

	public MultiExpresstion(AbstractExpresstion _left,
			AbstractExpresstion _right) {
		super(_left, _right);
		// TODO Auto-generated constructor stub
	}

	@Override
	public Float interpreter(HashMap<String, Float> var) {
		// TODO Auto-generated method stub
		return super.left.interpreter(var) * super.right.interpreter(var);
	}
}
public class DivExpresstion extends SymbolExpresstion {

	public DivExpresstion(AbstractExpresstion _left, AbstractExpresstion _right) {
		super(_left, _right);
		// TODO Auto-generated constructor stub
	}

	@Override
	public Float interpreter(HashMap<String, Float> var) {
		// TODO Auto-generated method stub
		return super.left.interpreter(var) / super.right.interpreter(var);
	}
}

逆波兰实现,具体就是统一的实现运算的,让计算表达式转换成为逆波兰表达式,然后可以实现按运算符运算顺序规则的运算。

public class RPN {

	private ArrayList<String> expression = new ArrayList<String>();// 存储中序表达式

	private ArrayList<String> right = new ArrayList<String>();// 存储右序表达式

	private AbstractExpresstion result;// 结果

	// 依据输入信息创建对象,将数值与操作符放入ArrayList中
	public RPN(String input) {
		StringTokenizer st = new StringTokenizer(input, "+-*/()", true);
		while (st.hasMoreElements()) {
			expression.add(st.nextToken());
		}
	}

	// 将中序表达式转换为右序表达式
	private void toRight() {
		Stacks aStack = new Stacks();
		String operator;
		int position = 0;
		while (true) {
			if (Calculate.isOperator((String) expression.get(position))) {
				if (aStack.top == -1
						|| ((String) expression.get(position)).equals("(")) {
					aStack.push(expression.get(position));
				} else {
					if (((String) expression.get(position)).equals(")")) {
						if (!((String) aStack.top()).equals("(")) {
							operator = (String) aStack.pop();
							right.add(operator);
						}
					} else {
						if (Calculate.priority((String) expression
								.get(position)) <= Calculate
								.priority((String) aStack.top())
								&& aStack.top != -1) {
							operator = (String) aStack.pop();
							if (!operator.equals("("))
								right.add(operator);
						}
						aStack.push(expression.get(position));
					}
				}
			} else
				right.add(expression.get(position));
			position++;
			if (position >= expression.size())
				break;
		}
		while (aStack.top != -1) {
			operator = (String) aStack.pop();
			right.add(operator);
		}
	}

	// 对右序表达式进行求值
	public void getResult(HashMap<String, Float> var) {
		this.toRight();
		Stack<AbstractExpresstion> stack = new Stack<AbstractExpresstion>();
		AbstractExpresstion op1, op2;
		String is = null;
		Iterator it = right.iterator();

		while (it.hasNext()) {
			is = (String) it.next();
			if (Calculate.isOperator(is)) {
				op2 = stack.pop();
				op1 = stack.pop();
				stack.push(Calculate.twoResult(is, op1, op2));
			} else
				stack.push(new VarExpresstion(is));
		}
		result = stack.pop();
		it = expression.iterator();
		while (it.hasNext()) {
			System.out.print((String) it.next());
		}
		System.out.println("=" + result.interpreter(var));
	}

	public static class Calculate {
		// 判断是否为操作符号
		public static boolean isOperator(String operator) {
			if (operator.equals("+") || operator.equals("-")
					|| operator.equals("*") || operator.equals("/")
					|| operator.equals("(") || operator.equals(")"))
				return true;
			else
				return false;
		}

		// 设置操作符号的优先级别
		public static int priority(String operator) {
			if (operator.equals("+") || operator.equals("-")
					|| operator.equals("("))
				return 1;
			else if (operator.equals("*") || operator.equals("/"))
				return 2;
			else
				return 0;
		}

		// 做2值之间的计算
		public static AbstractExpresstion twoResult(String op,
				AbstractExpresstion a, AbstractExpresstion b) {
			try {

				AbstractExpresstion result = null;
				if (op.equals("+"))
					result = new AddExpresstion(a, b);
				else if (op.equals("-"))
					result = new SubExpresstion(a, b);
				else if (op.equals("*"))
					result = new MultiExpresstion(a, b);
				else if (op.equals("/"))
					result = new DivExpresstion(a, b);
				else
					;
				return result;
			} catch (NumberFormatException e) {
				System.out.println("input has something wrong!");
				return null;
			}
		}
	}

	// 栈类
	public class Stacks {
		private LinkedList list = new LinkedList();
		int top = -1;

		public void push(Object value) {
			top++;
			list.addFirst(value);
		}

		public Object pop() {
			Object temp = list.getFirst();
			top--;
			list.removeFirst();
			return temp;

		}

		public Object top() {
			return list.getFirst();
		}
	}
}

底部的计算器:

public class Calculator {

	public Calculator() {
		float[][] dataSource = new float[3][6];
		System.out.println("data source:");
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 6; j++) {
				dataSource[i][j] = (float) (Math.random() * 100);
				System.out.print(dataSource[i][j] + ",");
			}
			System.out.println(";");
		}

		try {
			System.out.println("Input a expression:");
			BufferedReader is = new BufferedReader(new InputStreamReader(
					System.in));
			for (;;) {
				String input = new String();
				input = is.readLine().trim();
				if (input.equals("q"))
					break;
				else {
					RPN boya = new RPN(input);
					HashMap<String, Float> var;
					for (int i = 0; i < 3; i++) {
						var = new HashMap<String, Float>();
						var.put("a", dataSource[i][0]);
						var.put("b", dataSource[i][1]);
						var.put("c", dataSource[i][2]);
						var.put("d", dataSource[i][3]);
						var.put("e", dataSource[i][4]);
						var.put("f", dataSource[i][5]);

						boya.getResult(var);

					}

				}
				System.out
						.println("Input another expression or input 'q' to quit:");
			}
			is.close();
		} catch (IOException e) {
			System.out.println("Wrong input!!!");
		}

	}
}

测试类:

public class MainTest {

	public static void main(String[] args) {

		new Calculator();
	}
}

看一下输出吧,就是实现了表达式的运算:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
解释器模式(Interpreter Pattern)是一种行为型设计模式,它定义了一种语言文法的表示,并定义了一个解释器,用于解释语言中的句子。它将一个问题分成两个部分:一部分是语言的文法规则,另一部分是解释器,用来解释规则中的句子。解释器模式可以用于处理一些简单的语言,如数学表达式、正则表达式等。 实现方式: 1. 定义抽象表达式类(AbstractExpression),它是所有表达式类的父类,声明了抽象的解释方法。 2. 定义终结符表达式类(TerminalExpression),它实现了抽象表达式类中的解释方法,用于解释语言中的终结符。 3. 定义非终结符表达式类(NonterminalExpression),它也实现了抽象表达式类中的解释方法,用于解释语言中的非终结符。 4. 定义上下文类(Context),它包含了解释器需要的一些全局信息。 5. 客户端使用时,先创建一个上下文对象,然后将需要解释的语言句子作为参数传入解释器对象中,解释器对象将句子解释成相应的结果。 优点: 1. 可扩展性好,增加新的文法规则只需要添加相应的非终结符表达式类即可。 2. 易于实现语法分析。 缺点: 1. 对于复杂的文法规则,解释器模式的类数量可能会很大,增加程序的复杂性。 2. 执行效率较低,因为需要递归调用解释器对象。 适用场景: 1. 可以用于处理一些简单的语言,如数学表达式、正则表达式等。 2. 当语言的文法规则比较复杂时,可以使用解释器模式进行语法分析。 3. 当需要对语言进行增强时,可以使用解释器模式添加新的文法规则。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值