23 design modes Chapter 15: Java interpreter mode
Definition: Given a language, define a representation of its grammar, and define an interpreter that uses the representation to interpret sentences in the language.
Type: Behavioral Pattern
Class diagram:
The interpreter mode is a relatively rarely used mode, and I have never used this mode before. Let’s take a look at the interpreter mode.
Structure of interpreter mode
Abstract interpreter: Declare an abstract interface (or abstract class) to which all concrete expressions are to be implemented. The interface is mainly an interpret() method, called an explanation operation. The specific interpretation task is completed by its various implementation classes, and the specific interpreter is completed by the terminator interpreter TerminalExpression and the non-terminal interpreter NonterminalExpression respectively.
Terminator expression: implements interpretation operations associated with elements in grammar. Usually, there is only one terminator expression in an interpreter pattern, but there are multiple instances, corresponding to different terminators. Half of the terminator is an operation unit in the grammar. For example, there is a simple formula R=R1+R2, where R1 and R2 are terminators, and the corresponding interpreters that parse R1 and R2 are terminators.
Non-terminal expression: Each rule in the grammar corresponds to a non-terminal expression. Non-terminal expressions are generally operators or other keywords in the grammar. For example, in the formula R=R1+R2, + is a non-terminal character, and the interpreter of parsing + is a non-terminal character. Nonterminal expressions increase according to the complexity of the logic, and in principle each grammar rule corresponds to a nonterminal expression.
Environment Role: The task of this role is generally used to store the specific values corresponding to each terminator in the grammar, such as R=R1+R2. We assign 100 to R1 and 200 to R2. This information needs to be stored in the environment role. In many cases, we use Map to act as the environment role is enough.
Code implementation
class Context {} abstract class Expression { public abstract Object interpreter(Context ctx); } class TerminalExpression extends Expression { public Object interpreter(Context ctx){ return null; } } class NonterminalExpression extends Expression { public NonterminalExpression(Expression...expressions){ } public Object interpreter(Context ctx){ return null; } } public class Client { public static void main(String[] args){ String expression = ""; char[] charArray = expression.toCharArray(); Context ctx = new Context(); Stack<Expression> stack = new Stack<Expression>(); for(int i=0;i<charArray.length;i++){ //Make syntax judgment and call recursively} Expression exp = stack.pop(); exp.interpreter(ctx); } }The code part of grammatical recursion needs to be implemented according to the specific situation, so it is not reflected in the code. Abstract expressions are the key to generating a grammatical collection. Each non-terminal expression interprets a minimal syntax unit, and then recursively combines these syntax units into a complete grammar. This is the interpreter pattern.
Advantages and disadvantages of interpreter mode
The interpreter is a simple syntax analysis tool. Its most significant advantage is its extensibility. Modifying the syntax rules only requires modifying the corresponding non-terminal characters. If you expand the syntax, you only need to add a non-terminal character.
However, the interpreter pattern will cause the class to expand, and each syntax needs to produce a non-terminal expression. When the syntax rules are relatively complex, a large number of class files may be generated, which brings a lot of trouble to maintenance. At the same time, since the recursive call method is adopted, each non-terminal expression only cares about the expressions related to itself. Each expression needs to know the final result and must be recursive. Whether it is an object-oriented language or a process-oriented language, recursion is a not recommended way. Due to the use of a lot of loops and recursion, efficiency is a problem that cannot be ignored. Especially when used to interpret a parsing complex, lengthy syntax, efficiency is unbearable.
Applicable scenarios for interpreter mode
Interpreter mode can be used in the following cases:
There is a simple syntax rule, such as an SQL statement. If we need to perform rm conversion based on SQL statements, we can use the interpreter pattern to interpret the statement.
Some repetitive problems, such as the four operations of addition, subtraction, multiplication and division, but the formulas are different every time. Sometimes it is a+bc*d, sometimes it is a*b+cd, etc. The formulas are ever-changing, but they are all connected by the four non-terminal characters of addition, subtraction, multiplication and division. At this time, we can use the interpreter mode.
Things to note
The interpreter mode is really a relatively rarely used mode because it is too troublesome to maintain it. Imagine that if a bunch of non-terminal interpreters are not familiar with the rules of the grammar in advance, or the grammar is particularly simple, it will be difficult to understand its logic. The interpreter mode is rarely used in actual system development because it can cause problems such as efficiency, performance, and maintenance.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.