Design Pattern Sixteen - Interpreter Mode

Interpreter pattern is a behavioral design pattern, which is mainly used to deal with grammatical issues such as natural language or symbolic language. Its basic principle is to parse an expression into an abstract syntax tree, and then use the tree to perform specific operations. The following are the application scenarios, principles and Java examples of the interpreter mode:

Application scenario:

  1. Interpreter mode is used when you need to deal with grammatical issues such as natural language or symbolic language.
  2. Interpreter mode is used when you need to extend or modify some basic syntax constructs.
  3. Interpreter mode is used when you need to break down complex expressions into independent parts.

Rationale: The interpreter pattern is based on two core components: abstract expressions and contexts. AbstractExpression is an abstract class or interface that contains an interpret method that takes a context object as an argument and returns the interpreted result. A context is an object that contains information about the state of a program, which typically includes the program input and output that an interpreter is processing. The core of the interpreter pattern is to build an abstract syntax tree by using abstract expression objects, and use context objects to process the tree.

Java example: The following is a simple Java example that demonstrates how to use the interpreter mode. Suppose there is a simple language that supports addition, subtraction, multiplication, and division. You need to write a program to parse and evaluate expressions in this language.

First, we create an abstract expression class that contains an explain method:

public abstract class Expression {
    public abstract int interpret(Context context);
}

Then, we implement four concrete expression classes for handling addition, subtraction, multiplication, and division operations:

public class AddExpression extends Expression {
    private Expression leftExpression;
    private Expression rightExpression;
    public AddExpression(Expression leftExpression, Expression rightExpression) {
        this.leftExpression = leftExpression;
        this.rightExpression = rightExpression;
    }
    public int interpret(Context context) {
        return leftExpression.interpret(context) + rightExpression.interpret(context);
    }
}

public class SubtractExpression extends Expression {
    private Expression leftExpression;
    private Expression rightExpression;
    public SubtractExpression(Expression leftExpression, Expression rightExpression) {
        this.leftExpression = leftExpression;
        this.rightExpression = rightExpression;
    }
    public int interpret(Context context) {
        return leftExpression.interpret(context) - rightExpression.interpret(context);
    }
}

public class MultiplyExpression extends Expression {
    private Expression leftExpression;
    private Expression rightExpression;
    public MultiplyExpression(Expression leftExpression, Expression rightExpression) {
        this.leftExpression = leftExpression;
        this.rightExpression = rightExpression;
    }
    public int interpret(Context context) {
        return leftExpression.interpret(context) * rightExpression.interpret(context);
    }
}

public class DivideExpression extends Expression {
    private Expression leftExpression;
    private Expression rightExpression;
    public DivideExpression(Expression leftExpression, Expression rightExpression) {
        this.leftExpression = leftExpression;
        this.rightExpression = rightExpression;
    }
    public int interpret(Context context){
    int divisor = rightExpression.interpret(context);
    if (divisor == 0) {
        throw new ArithmeticException("division by zero");
    } else {
        return leftExpression.interpret(context) / divisor;
    }
}

Finally, we create a context object and a parser object, then use the parser object to parse the expression and output the result:

public class InterpreterDemo {
    public static void main(String[] args) {
        String expression = "2 3 4 + *";
        Context context = new Context();
        Parser parser = new Parser(expression);
        Expression parseTree = parser.parse();
        int result = parseTree.interpret(context);
        System.out.println(result);
    }
}

In this example, we first create a string expression, then create a context object and a parser object. Next, we use the parser object to parse the expression and produce an abstract syntax tree. Finally, we execute the interpret method of the interpreter object, passing it the context object. This method will walk the abstract syntax tree and perform all calculations, and finally return the result and output it. In summary, the interpreter pattern is a very useful design pattern that helps you parse and execute syntactic problems such as natural language or symbolic language. Its principle is to use abstract expressions and context objects to build an abstract syntax tree, and use the tree to perform specific operations. In Java, you can use abstract classes and interfaces to implement these components, and use them to build concrete expression objects and interpreter objects, etc.

Tags: Java Design Pattern

Posted by iyia12co on Sat, 04 Mar 2023 21:58:56 +0530