This is the last interpreter of learning. To make a long story short. The interpreter mode is used to solve specific types of problems with high frequency, and has certain similarity and regularity. For example, a calculator. This model is less likely to be used in actual development. But it is also necessary to learn, because it can help us understand some source code. For example, Spring EL expressions and regular expressions.
Definition of Interpreter pattern: define a language for the analysis object, define the grammatical representation of the language, and then design a parser to interpret the sentences in the language. In other words, use the compiled language to analyze the examples in the application. This pattern implements an interface for grammar expression processing that interprets a specific context.
advantage:
- Good scalability. Because classes are used to represent the grammar rules of the language in the interpreter mode, the grammar can be changed or extended through mechanisms such as inheritance.
- Easy to implement. Each expression node class in the syntax tree is similar, so it is easier to implement its grammar.
Disadvantages:
- Low execution efficiency. Interpreter mode usually uses a large number of loops and recursive calls. When the sentences to be interpreted are complex, its running speed is very slow, and the debugging process of the code is also troublesome. Will cause class expansion.
- Each rule in the Interpreter pattern needs to define at least one class. When there are many grammar rules, the number of classes will increase sharply, making it difficult for the system to manage and maintain.
- There are few applicable scenarios. In software development, there are very few application examples that need to define language grammar, so this model is rarely used.
Structure and implementation of pattern
structure
- Abstract Expression role: defines the interface of the interpreter and specifies the interpretation operation of the interpreter, mainly including the interpretation method interpret().
- Terminator expression (Terminal) Expression role: it is a subclass of abstract expression, which is used to realize the operations related to terminators in grammar. Each terminator in grammar has a specific terminator expression corresponding to it.
- Non terminal expression role: it is also a subclass of abstract expression, which is used to realize the operations related to non terminal in grammar. Each rule in grammar corresponds to a non terminal expression.
- Context role: it usually contains the data or public functions required by each interpreter. It is generally used to transfer the data shared by all interpreters. Subsequent interpreters can obtain these values from here.
- Client (Client): the main task is to translate the sentences or expressions that need analysis into the abstract syntax tree described by the interpreter object, then invoke the interpreter's interpretation method, and of course, can indirectly access the interpreter's interpretation method through the role of the environment.
realization
Implementation scenario: the interpreter mode is used to interpret expressions to realize calculator functions (including addition and subtraction only)
package com.wly.DesignPatterns; import java.util.Stack; /** * @program: StudyDome * @author: yuanzhang * @create: 2021-01-26 15:22 **/ public class InterpreterPattern { public static void main(String[] args) { CalculateUtil calculateUtil = new CalculateUtil(); String expression = "9+8+7-8-7-6"; calculateUtil.parse(expression); float result = calculateUtil.calculate(); System.out.println(expression+"="+result); } } /** * @Annotation:Abstract expression * @Author: yuanzhang * @Date: 15:23 */ interface AbstractExpression{ public float interpret(); } /** * @Annotation:End expressions: storing numbers * @Author: yuanzhang * @Date: 15:56 */ class NumberExpression implements AbstractExpression{ private float number; public NumberExpression(float number) { this.number = number; } public NumberExpression(String number) { this.number = Integer.parseInt(number); } @Override public float interpret() { return number; } } /** * @Annotation:Nonterminal expressions: addition * @Author: yuanzhang * @Date: 15:56 */ class AddExpression implements AbstractExpression{ private AbstractExpression e1,e2; public AddExpression(AbstractExpression e1, AbstractExpression e2) { this.e1 = e1; this.e2 = e2; } @Override public float interpret() { //Perform addition return e1.interpret()+e2.interpret(); } } /** * @Annotation:Nonterminal expressions: subtraction * @Author: yuanzhang * @Date: 15:59 */ class SubtractionExpression implements AbstractExpression{ private AbstractExpression e1,e2; public SubtractionExpression(AbstractExpression e1, AbstractExpression e2) { this.e1 = e1; this.e2 = e2; } @Override public float interpret() { //Perform subtraction return e1.interpret()-e2.interpret(); } } class CalculateUtil{ private AbstractExpression expression; public void parse(String expression){ String[] strings = expression.split(""); Stack<AbstractExpression> stack = new Stack <AbstractExpression>(); for (int i = 0; i < strings.length; i++) { //If it's an addition operator if (strings[i].equals("+")){ //Get the data at the top of the stack AbstractExpression e1 = stack.pop(); //Gets the next expression AbstractExpression e2 = new NumberExpression(strings[++i]); //Judge next data //Add stack.push(new AddExpression(e1,e2)); }else if (strings[i].equals("-")){ //subtraction operator //Get the data at the top of the stack AbstractExpression e1 = stack.pop(); //Gets the next expression AbstractExpression e2 = new NumberExpression(strings[++i]); //Add stack.push(new SubtractionExpression(e1,e2)); }else{ stack.push(new NumberExpression(strings[i])); } } //Keep the final result this.expression = stack.pop(); } public float calculate(){ return expression.interpret(); } }
Output:
9+8+7-8-7-6=3.0