Object-Oriented Design Patterns (13), Interpreter Patterns

Interpreter mode, literally, is to construct an interpreter for a grammar (a statement or expression in the form of a specific grammar), which is used to interpret the grammar, so that such a grammar with certain writing rules can express Specific functions, such specific writing rules are also commonly referred to as grammars, such as C/C++, Java, Python and other computer languages ​​have their own grammars. Also, some interpreted languages ​​such as Python. It needs a Python interpreter when it is executed, which is also an interpreter.

Definition: The interpreter pattern writes an interpreter for some grammar with specific writing rules that make it meaningful.

scenes to be used:

  1. as an interpreter .

    Explain the function or meaning of a statement with a specific syntax. Such as interpreting a statement with specific writing rules, in the following example, it is used as an interpreter to interpret an arithmetic expression.

  2. as a translator or decoder . Such as constants in high-level languages, the compiler system will replace the constants with the numbers it represents when compiling, and similarly we can also define some specific statements with a certain meaning. Then use the corresponding interpreter to interpret it.

Suppose there is such an expression or statement a_+_b_-_c, we want to know its meaning, if we specify that the _ symbol is used to separate numbers and operators, then the above statement means to calculate a+bc. This is when students take exams. They stipulate that 1 means A, 2 means B, 3 means C, and 4 means D to pass multiple-choice answers, which is similar to the encoding and decoding process. In fact, the decoder is also the interpreter, so we use the code to interpret the meaning of the above expression.

Code:

abstract interpreter (base class)

/**
 * 主要的解释器。是全部解释器的基类
 * @author lt
 *
 */
public abstract class BaseInterpreter<T> {

    /**
     * 抽象解释方法
     * @return
     */
    public abstract T interpret();
}

Extracted commonalities of interpreters

Integer interpreter (interprets integers)

/**
 * 整数解释器
 * @author lt
 *
 */
public class NumberInterpreter extends BaseInterpreter<Integer>{

    private int num;

    public NumberInterpreter(int num){
        this.num = num;
    }

    @Override
    public Integer interpret() {
        return this.num; // 自己主动装箱拆箱
    }
}

Interpret the integer and return the integer directly. The integer here is the terminator

operator interpreter (base class )

/**
 * 二目运算符操作解释器,也是一个基类,由于有好多的二目运算符
 * @author lt
 *
 */
public abstract class OperatorInterpreter extends BaseInterpreter<Integer>{

    protected BaseInterpreter<Integer> exp1;
    protected BaseInterpreter<Integer> exp2;

    public OperatorInterpreter(BaseInterpreter<Integer> exp1,BaseInterpreter<Integer> exp2){
        this.exp1 = exp1;
        this.exp2 = exp2;
    }

}

Explain the binary operator. Two integers are required, for the nonterminal interpreter.

Addition interpreter (compute addition)

/**
 * 加法解释器。计算加法
 * @author lt
 *
 */
public class AdditionInterpreter extends OperatorInterpreter{

    public AdditionInterpreter(BaseInterpreter<Integer> exp1,
            BaseInterpreter<Integer> exp2) {
        super(exp1, exp2);
    }

    /**
     * 用来计算加法
     */
    @Override
    public Integer interpret() {
        return exp1.interpret() + exp2.interpret();
    }
}

Subtraction interpreter (compute subtraction)

/**
 * 减法计算器
 * @author lt
 *
 */
public class SubtractionInterpreter extends OperatorInterpreter{

    public SubtractionInterpreter(BaseInterpreter<Integer> exp1,
            BaseInterpreter<Integer> exp2) {
        super(exp1, exp2);
    }

    @Override
    public Integer interpret() {
        return exp1.interpret() - exp2.interpret();
    }
}

calculator, translate a_+_b_-_c (calculation expression)

import java.util.Stack;

/**
 * 计算器
 * @author lt
 *
 */
public class Calculator {

    private Stack<BaseInterpreter<Integer>> mExpStack = new Stack<BaseInterpreter<Integer>>();

    public Calculator(String expression){
        // 声明两个BaseInterpreter<Integer>的暂时变量,由于计算必须要记录两个数
        BaseInterpreter<Integer> exp1,exp2;

        //  以符号_分隔,这是我们自己规定的
        String[] exps = expression.split("_");

        for(int i=0;i<exps.length;i++){
            switch (exps[i].charAt(0)) {
            case '+': // 加法
                exp1 = mExpStack.pop();
                exp2 = new NumberInterpreter(Integer.valueOf(exps[++i]));
                mExpStack.push(new AdditionInterpreter(exp1, exp2));
                break;
            case '-':
                exp1 = mExpStack.pop();
                exp2 = new NumberInterpreter(Integer.valueOf(exps[++i]));
                mExpStack.push(new SubtractionInterpreter(exp1, exp2));
                break;
            default: // 数字
                mExpStack.push(new NumberInterpreter(Integer.valueOf(exps[i])));
                break;
            }
        }
    }

    /**
     * 计算
     * @return
     */
    public int calculate(){
        return mExpStack.pop().interpret();
    }
}

This class is used to translate the meaning of sentences with formal structures such as a_+_b_-_c. The symbol _ here is what I specify to separate numbers, of course, you can also specify other symbols as separators.

The method of this class is also very easy. In the construction method, the expressions are first separated by the symbol _. Get some operators and numbers, and then infer whether it is a + operator or a - operator or a number based on the type of the first character of the separated string, assuming it is a + operator. Then it pops the stored number off the stack and records it to exp1, then gets the string after the operator (it must be a number) and records it to the variable exp2. Finally, use the addition interpreter to interpret the numbers recorded by these two variables and push them into the stack. When the next loop is performed, the pop-up and the next number are calculated; if it is the - operator, then it is the same as the + operator, just use is a subtraction interpreter; assuming a number, it is directly pushed onto the stack, and the whole process is a step-by-step calculation process. The calculate method is used to output the calculation result.

Test :

public class Test {

    public static void main(String[] args) {
        String testStr = "1_+_34_-_10_+_50";
        Calculator calculator = new Calculator(testStr);
        System.out.println("result="+calculator.calculate());
    }
}

result:

Write picture description here

 It can be seen that the interpreter we defined successfully interprets a statement in the form of a_+_b_-_c. In fact, the function implemented by this interpreter is similar to the function of decoding or translation. But then again, despite successfully explaining that form of statement, it can only calculate addition and subtraction of integers. If you want to do other operations or other types of numbers, such as multiplication and division and floating point, you need to add the corresponding interpreter, but if it involves mixed operations, it is more complicated, and you have to consider the priority. At this time, such a mode may not be suitable, that is to say, the interpreter mode is suitable for simple statements.

Summary :

Advantages:

  • Flexible scalability .

    When we extend and extend the grammar rules, we only need to add the corresponding non-terminal symbol interpreter (such as the addition and subtraction interpreter above), and use the newly added interpreter object (such as adding and subtracting) when constructing the abstract syntax tree. interpreter) for a detailed explanation (calculation of subtraction), which is very convenient. Nonterminal symbols are symbols that have not yet ended. They are binary operators, as the addition and subtraction interpreters in the following example interpret the addition and subtraction respectively. There must be two numbers on both sides.

shortcoming:

  • The number of classes expands, making it difficult to maintain later . Since each grammar corresponds to at least one interpreter class, a large number of classes will be generated, which will lead to difficulties in later maintenance. At the same time, for complex grammars, it will be cumbersome to construct its abstract syntax tree, and even multiple syntax trees need to be constructed, so. Interpreter mode is not recommended for complex grammars.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326281232&siteId=291194637