Twenty-three Classical Design Patterns-39-Interpreter Patterns

Keywords: calculator Java

1. Interrepeter Pattern

Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.

1.1 Interpreter Model - Core Ideas

Define a new language and specify how to parse it.

1.2 Interpreter Schema-Class Diagram

The parser has four roles:

  • AbstractExpression: An Abstract parser that defines an abstract method. There is only one abstract method
  • TerminalExpress: TerminalExpress: TerminalExpress. Usually there is only one TerminalExpress in an analytic schema.
  • NonterminalExpression: Non-terminal expression.
  • Context: Context, which contains global information beyond the parser.

1.3 Interpreter Patterns - Advantages and Disadvantages

  • Advantages: Extension number, modification of grammar rules only needs to modify the corresponding non-terminal expression.
  • Disadvantages:
    • Parser patterns cause class expansion
    • The parser mode uses recursive invocation, which is inefficient.
    • perceptual difficulty

1.4 Interpreter Patterns - Applicable Scenarios

  • A Simple Grammar Scenario to Explain
  • Repeated problems can be applied to the interpreter model

1.5 Notes

  • In project development, try not to apply interpreter model.
  • If parser mode is needed in java development, you can refer to open source parsing toolkits such as Expression4J, Jep, MESP(Math Expression String Parser) and repeat wheels every time.

2. Parser pattern - application examples

The parser pattern is rarely used, so the author directly extracts an example of addition and subtraction from the book.

Class 2.1 Graphs

2.2 Abstract Expression

// Abstract expression class
public abstract class Expression {

    // Analytical formulas and values, where the key value in var is the parameter in the formula and value is the specific value
    public abstract int interpreter(HashMap<String, Integer> var);
}

2.3 Terminator expression - VarExpression

// variable resolver
public class VarExpression extends Expression {

    private String key;

    public VarExpression(String key) {
        this.key = key;
    }

    @Override
    public int interpreter(HashMap<String, Integer> var) {
        return var.get(key);
    }
}

2.4 Symbol Expression

// Abstract symbol parser
public abstract class SymbolExpression extends Expression {

    protected Expression left;

    protected Expression right;

    public SymbolExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

}

2.5 AddExpression

// Additive parser
public class AddExpression extends SymbolExpression {
    public AddExpression(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpreter(HashMap<String, Integer> var) {
        return super.left.interpreter(var) + super.right.interpreter(var);
    }
}

2.6 SubExpression

// Subtraction parser
public class SubExpression extends SymbolExpression {
    public SubExpression(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpreter(HashMap<String, Integer> var) {
        return super.left.interpreter(var) - super.right.interpreter(var);
    }
}

2.7 Calculator

public class Calculator {

    // Expression
    private Expression expression;

    public Calculator(String expStr) {

        // Define a stack, arrange operators in order
        Stack<Expression> stack = new Stack<>();

        // Expressions are split 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 results are put on the stack
                    left = stack.pop();
                    right = new VarExpression(String.valueOf(charArray[++i]));
                    stack.push(new AddExpression(left, right));
                    break;
                case '-':
                    left = stack.pop();
                    right = new VarExpression(String.valueOf(charArray[++i]));
                    stack.push(new SubExpression(left, right));
                    break;
                default:
                    stack.push(new VarExpression(String.valueOf(charArray[i])));
            }
        }

        // Throw out the calculation results.
        this.expression =  stack.pop();

    }

    // Start the operation
    public int run(HashMap<String, Integer> var) {
        return this.expression.interpreter(var);
    }
}

2.8 Test

    @Test
    public void test(){

        // Expression
        String expStr = "a+b-c";

        // Variable value
        HashMap<String, Integer> map = new HashMap<>();
        map.put("a", 10);
        map.put("b", 5);
        map.put("c", 1);

        // Calculator
        Calculator calculator = new Calculator(expStr);

        // Calculation
        int result = calculator.run(map);

        System.out.println(expStr + "=" + result);
    }

2.9 Test Output

a+b-c=14

Posted by sheephat on Tue, 27 Aug 2019 02:22:49 -0700