1. The scenario is resolved

1.1 Scenario Description

Problems encountered in big data statistical projects: The general calculation model is one or more calculation formulas for the statistics, analysis and prediction of existing data according to the calculation model, which usually consists of four operations, namely addition, subtraction, multiplication and division. The calculation model needs to be edited during operation and the design scheme needs to be highly extensible

1.2 OO design

1.3 Demand Change

1.4 Bringing Problems

2. Improve with design patterns

2.1 analysis

The computational model is written in the normal arithmetic way, and the interpreter handles the syntax. There are two types of symbols in the logical computational model: data and operators

2.2 Redesign

2.3 the source code

- cls 该包为各种逆波兰之后的各种计算方式
- - AbstractExpresstion 抽象类,所有的超类(HashMap<String, Float> 为一列数据)
- - - VarExpresstion 终结表达式(变量表达式)
- - - SymbolExpresstion 非终结表达式(符号表达式,抽象类)
- - - - AddExpresstion 加
- - - - SubExpresstion 减
- - - - MultiExpresstion 乘
- - - - DivExpresstion 除


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


public class VarExpresstion extends AbstractExpresstion {
	private String key;

	public VarExpresstion(String _key) {
		this.key = _key;
	}

	@Override
	public Float interpreter(HashMap<String, Float> var) {
		return var.get(this.key);
	}
}

public abstract class SymbolExpresstion extends AbstractExpresstion {
	protected AbstractExpresstion left;
	protected AbstractExpresstion right;

	public SymbolExpresstion(AbstractExpresstion _left,AbstractExpresstion _right) {
		this.left = _left;
		this.right = _right;
	}
}


public class AddExpresstion extends SymbolExpresstion {
	public AddExpresstion(AbstractExpresstion _left, AbstractExpresstion _right) {
		super(_left, _right);
	}

	@Override
	public Float interpreter(HashMap<String, Float> var) {
		return super.left.interpreter(var) + super.right.interpreter(var);
	}
}


public class SubExpresstion extends SymbolExpresstion {
	public SubExpresstion(AbstractExpresstion _left, AbstractExpresstion _right) {
		super(_left, _right);
	}

	@Override
	public Float interpreter(HashMap<String, Float> var) {
		return super.left.interpreter(var) - super.right.interpreter(var);
	}
}



public class MultiExpresstion extends SymbolExpresstion {
	public MultiExpresstion(AbstractExpresstion _left,
			AbstractExpresstion _right) {
		super(_left, _right);
	}

	@Override
	public Float interpreter(HashMap<String, Float> var) {
		return super.left.interpreter(var) * super.right.interpreter(var);
	}
}



public class DivExpresstion extends SymbolExpresstion {
	public DivExpresstion(AbstractExpresstion _left, AbstractExpresstion _right) {
		super(_left, _right);
	}

	@Override
	public Float interpreter(HashMap<String, Float> var) {
		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();
		}
	}
}

Copy the code
  • Calculator,InterpreterTest
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 InterpreterTest { public static void main(String[] args) { new Calculator(); }}Copy the code

After executing the Test class, type in the console: A, b, C, D, e, f are the operation formulas that can contain +-*/(), and press Enter to get the result.

3. Summary of design patterns

3.1 define

The interpreter pattern defines a syntax, defines an interpreter, and the interpreter takes that syntactic sentence and expresses some complex problem as a syntactic rule, and then builds the interpreter to interpret and process those kinds of sentences

3.2 Analysis

3.3 the advantages and disadvantages

  • advantages
    • Easy to modify, modify the grammar rules as long as the corresponding non-terminal can be modified
    • Easy to expand, expand the syntax, as long as the addition of non-terminal classes can be
  • Disadvantages:
    • The representation of a complex syntax creates a complex class hierarchy, which is difficult to manage and maintain
    • The interpreter is recursive and inefficient

4. Design pattern usage scenarios and attention

4.1 Precautions:

The interpreter pattern is rarely used in actual system development. Consider open source parsing toolkits such as Expression4J, MESP, and Jep

4.2 Application:

Some data analysis tools, report design tools, scientific calculation tools, etc., when you have a simple syntax and efficiency is not an issue

5. Refer to the article

Total content in HeadFirst design mode and related videos