This is the 10th day of my participation in Gwen Challenge

Interpreter mode

The interpreter pattern is a behavioral pattern that provides a way to interpret the syntax and expressions of a language, defining an expression interface through which to interpret a particular context. But there are actually few and relatively rare scenarios that use the interpreter pattern. However, since it is one of the design patterns, there must also be unique patterns that it can use.

Given a language, define a representation of its grammar and define an interpreter that uses that representation to interpret sentences in the language.

implementation

A common scenario for interpreters is the interpretation of arithmetic expressions. For example, if the expression m + n + p is interpreted in interpreter mode, the number M /n/p can be used as a terminator, and the + can be used as a non-terminator.

The ArithmeticExpression abstract class defines a interpret method. NumExpression is used to interpret and obtain numbers. OperatorExpression is an abstract class that declares two arithmeticexpressions to store the numeric interpreter on either side of the NumExpression operator. AdditionExpression inherits OperatorExpression which implements the role of the addition interpreter.

After implementing the interpreter that parses each structure in the grammar, create a Calculator class to handle the logic. Input the whole grammar content: “153 + 896 + 789”, continuously divide and parse the content into each corresponding interpreter through segmentation, and finally assemble the interpreter and output the final result.

public abstract class ArithmeticExpression {
    /** * Abstract parsing methods * Concrete parsing logic implemented by concrete subclasses **@returnParse to a specific value */
    public abstract int interpret(a);
}

public class NumExpression extends ArithmeticExpression {

    private int num;

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

    @Override
    public int interpret(a) {
        returnnum; }}public abstract class OperatorExpression extends ArithmeticExpression {

    public ArithmeticExpression exp1;
    public ArithmeticExpression exp2;

    public OperatorExpression(ArithmeticExpression exp1, ArithmeticExpression exp2) {
        this.exp1 = exp1;
        this.exp2 = exp2; }}public class AdditionExpression extends OperatorExpression {

    public AdditionExpression(ArithmeticExpression exp1, ArithmeticExpression exp2) {
        super(exp1, exp2);
    }

    @Override
    public int interpret(a) {
        returnexp1.interpret() + exp2.interpret(); }}public class Calculator {

    // Declare a Stack to store and operate all related interpreters
    private Stack<ArithmeticExpression> mExpStack = new Stack<>();

    public Calculator(String expression) {
        // Declare two ArithmeticExpression temporary variables that store the numeric interpreters on the left and right sides of the operator
        ArithmeticExpression exp1;
        ArithmeticExpression exp2;
        // Split expression strings by Spaces
        String[] elements = expression.split("");

        /** * loop over the expression string */
        for (int i = 0; i < elements.length; i++) {
            /** * determine the operation symbol */
            switch (elements[i].charAt(0)) {
                case '+': // If it is a plus sign
                    // Pops the interpreter on the stack as the interpreter to the left of the operation symbol
                    exp1 = mExpStack.pop();
                    // Construct a numeric parser from the element below the operand array subscript
                    exp2 = new NumExpression(Integer.valueOf(elements[++i]));
                    // Construct the addition interpreter using the two number interpreters above
                    mExpStack.push(new AdditionExpression(exp1, exp2));
                    break;
                default: // If it is a number
                    /** * is a number if it is not an operation symbol * if it is a number, construct the number interpreter directly and push */
                    mExpStack.push(new NumExpression(Integer.valueOf(elements[i])));
                    break; }}}public int calculate(a) {
        return mExpStack.pop().interpret();
    }
}

Calculator calculator = new Calculator(153 + 896 + 789);
calculator.calculate();
Copy the code

conclusion

  1. Advantage of interpreter mode: Flexible extensibility. When extending grammar rules, you only need to add corresponding non-terminal interpreter, and use the new interpreter object to interpret the abstract syntax tree.
  2. Advantage of interpreter mode: There must be at least one interpreter for each provision, and the number of classes is large, which makes it difficult to maintain. If the grammar is complex and abstract, then building an alternative that uses the interpreter pattern is not very appropriate.

reference

  • Android Source Code Design Patterns