1. Definitions
Interpreter mode is a behavioral mode, which is basically unavailable in work. Its function is to give a language and define an interpreter, which uses the representation to interpret sentences in the language.
Now there is a demand, probably a calculator. First, give a formula, and then enter the corresponding value to calculate the final result. The formula is not complex and can only support + and - operations. For example, enter a+b-c, 100, 200, 100, and the calculation result is 200. The a+b-c we input can actually be understood as another language, so an interpreter is needed to interpret the syntax and calculate the results.
Now we need to analyze the elements in the formula, including operators and values involved in the operation. In fact, for the interpreter, we only need to explain the operators and values involved in the operation. Of course, there may be various operators for the operators. For example, addition and subtraction actually correspond to different calculation rules.
2. Interpreter mode structure diagram
VarExpression is used to parse the operation value. The number of operation elements of each formula is different. Each operation element corresponds to a VarExpression object. SybmolExpression is responsible for operation symbol parsing. It is implemented by two subclasses, addressexpression (responsible for addition operation) and SubExpression (responsible for subtraction operation).
The Calculator class is used to arrange the order of operations (addition and subtraction are not considered, but multiplication and division? Pay attention to scalability) and return results. Therefore, we need to add a encapsulation class to handle encapsulation. Because we only perform operations, we are not linked to business for the time being.
![](/images/think/8d9800fec7ceb4d34636dc1b8cb6267f.jpg)
3. Interpreter mode implementation
The Expression abstract class only defines a method interpreter method for calculation. Of course, the calculation logic is implemented by subclasses, and the key stored in the parameter HashMap is the parameter in the formula, such as a, b and c, while value represents the specific value of the used parameter.
public abstract class Expression { //Analyze the formula and value, where the key value in var is the parameter in the formula, such as a, b and c, and the value value is a specific number public abstract int interpreter(HashMap<String,Integer> var); }
VarExpression is the specific implementation of Expression, which is used to analyze the specific operation values in the formula, such as the specific corresponding values of a, b and c. of course, the specific values are obtained from HashMap through key.
public class VarExpression extends Expression { private String key; public VarExpression(String key) { this.key = key; } //Take it from the map @Override public int interpreter(HashMap<String, Integer> var) { return var.get(this.key); } }
SymbolExpression is also a concrete implementation of Expression. It is used to parse formula operators. Of course, for operators, you must know who is on the left and who is on the right. Otherwise, how to calculate.
public abstract class SymbolExpression extends Expression { protected Expression left; protected Expression right; //All analytical formulas should only care about the results of their left and right expressions public SymbolExpression(Expression left, Expression right) { this.left = left; this.right = right; } }
Address expression is a concrete operator parser and a concrete implementation of SymbolExpression. For SymbolExpression, only the left and right parts of the operation need to be defined, and the actual addition or subtraction is done by subclasses. Therefore, address expression is to add the left and right parts.
public class AddExpression extends SymbolExpression { public AddExpression(Expression left, Expression right) { super(left, right); } //Add up the results of the left and right expressions @Override public int interpreter(HashMap<String, Integer> var) { return left.interpreter(var) + right.interpreter(var); } }
Instead, SubExpression subtracts the left and right parts of the operator.
public class SubExpression extends SymbolExpression { public SubExpression(Expression left, Expression right) { super(left, right); } //Subtract the left and right expressions @Override public int interpreter(HashMap<String, Integer> var) { return left.interpreter(var) - right.interpreter(var); } }
The Calculator constructor accepts an expression, then converts the expression into a char array, and judges the operation symbol. If it is "+", it calls addressexpression, and puts the number on the left (left variable) and the number on the right (right variable) into addressexpression. And stored in the stack.
Why is the number on the left in the stack? The reason is that it is put into the stack to make the calculation sequential. For example, a+b-c. if there is already an a+b address expression in the stack, then (a+b) should be put into the SubExpression as the left and C as the right.
public class Calculator { //Defined expression private Expression expression; //Constructor passes parameters and parses them public Calculator(String expStr) { //Define a stack and arrange the order of operations Stack<Expression> stack = new Stack<Expression>(); //Split expression into character arrays char[] charArray = expStr.toCharArray(); //operation Expression left = null; Expression right = null; for (int i = 0; i < charArray.length; i++) { switch (charArray[i]) { case '+': //addition //Get the left value of addition, such as a+b-c, get a left = stack.pop(); //Get the right value of addition, such as a+b-c, get b right = new VarExpression(String.valueOf(charArray[++i])); //Store the adding entity on the stack stack.push(new AddExpression(left, right)); break; case '-': //Get the left value of subtraction, such as a+b-c, get (a+b) left = stack.pop(); //Get the right value of subtraction, such as a+b-c, get c right = new VarExpression(String.valueOf(charArray[++i])); //Store the subtracted entity on the stack stack.push(new SubExpression(left, right)); break; default: //The variable in the formula, i.e. a or b or c stack.push(new VarExpression(String.valueOf(charArray[i]))); } } //Take out the entities to be calculated, such as a+b-c, and get the entities of (a+b) and (a+b)-c this.expression = stack.pop(); } //Start operation public int run(HashMap<String, Integer> var) { return this.expression.interpreter(var); } }
The Test class is used to simulate the user's situation. The user's requirements can be extended and the formula can be modified. It can be handled by accepting keyboard events. The source code of the Client class is as follows.
public class Test { //Run four operations public static void main(String[] args) throws IOException { String expStr = getExpStr(); //assignment HashMap<String,Integer> var = getValue(expStr); Calculator cal = new Calculator(expStr); System.out.println("The calculation result is:"+expStr +"="+cal.run(var)); } //Get expression public static String getExpStr() throws IOException{ System.out.print("Please enter an expression:"); return (new BufferedReader(new InputStreamReader(System.in))).readLine(); } //Get value mapping public static HashMap<String,Integer> getValue(String exprStr) throws IOException { HashMap<String, Integer> map = new HashMap<String, Integer>(); //Parsing has several parameters to pass for (char ch : exprStr.toCharArray()) { if (ch != '+' && ch != '-') { if (!map.containsKey(String.valueOf(ch))) { //Solve the problem of duplicate parameters System.out.print("Please enter" + ch + "Value of:"); String in = (new BufferedReader(new InputStreamReader(System.in))).readLine(); map.put(String.valueOf(ch), Integer.valueOf(in)); } } } return map; } }
Please enter an expression: a+b-c Please enter a Value of:100 Please enter b Value of:200 Please enter c Value of:20 The calculation result is: a+b-c=280
Roles in interpreter mode
AbstractExpression (Abstract interpreter), the specific interpretation task is completed by each implementation class.
Concreteexpression (concrete interpreter) concrete interpreters are divided into two categories: TerminalExpression: Terminator expression, which implements the interpretation operation associated with elements in grammar. Usually, there is only one terminator expression in an interpreter mode, but there are multiple instances corresponding to different terminators. Specifically, our example is the VarExpression class. Each terminator in the expression generates a VarExpression object in the stack. Nonterminalexpression (non terminal expression). Each rule in the grammar corresponds to a non terminal expression. Our example is that the addition and subtraction rules correspond to two classes, addressexpression and SubExpression. Non terminator expressions increase according to the complexity of logic. In principle, each grammar rule corresponds to a non terminator expression. Context (environment role) is replaced by HashMap in our example.
Reference: Zen of design pattern
Code acquisition address: https://gitee.com/bughong/design-pattern