1. Definition

The Interpreter pattern provides a way to evaluate language grammars or expressions for particular languages. It involves turning a language into a series of well-defined objects in the system, thus making the language easier to manipulate and extend.

2. Problem Statement

Imagine you are building a software that needs to understand and evaluate simple mathematical expressions like “5 + 3” or “4 – 2”. Instead of writing complex if-else logic and parsing strings, how can you make the system easily understand these expressions?

3. Solution

Interpreter suggests modeling the domain with classes. Each rule of the grammar or language becomes a separate class. By organizing and composing these classes, you can interpret (or evaluate) sentences in the language.

4. Real-World Use Cases

1. Regular expressions evaluation.

2. Parsing and evaluating simple mathematical expressions.

3. SQL parsers in databases.

5. Implementation Steps

1. Create an abstract expression class or interface.

2. Implement concrete classes for every rule or token in the grammar.

3. Interpret the sentence or expression by using a tree of these classes.

6. Implementation in Java

// Expression Interface
interface Expression {
    int interpret();
}

// Terminal Expressions
class Number implements Expression {
    private int number;
    public Number(int number) {
        this.number = number;
    }
    @Override
    public int interpret() {
        return number;
    }
}

// Non-Terminal Expressions
class Add implements Expression {
    private Expression leftExpression;
    private Expression rightExpression;
    public Add(Expression left, Expression right) {
        leftExpression = left;
        rightExpression = right;
    }
    @Override
    public int interpret() {
        return leftExpression.interpret() + rightExpression.interpret();
    }
}

class Subtract implements Expression {
    private Expression leftExpression;
    private Expression rightExpression;
    public Subtract(Expression left, Expression right) {
        leftExpression = left;
        rightExpression = right;
    }
    @Override
    public int interpret() {
        return leftExpression.interpret() - rightExpression.interpret();
    }
}

// Client
public class Client {
    public static void main(String[] args) {
        Expression add = new Add(new Number(5), new Number(3));
        System.out.println(add.interpret());  // Outputs 8

        Expression subtract = new Subtract(new Number(5), new Number(3));
        System.out.println(subtract.interpret());  // Outputs 2
    }
}

Output:

8
2

Explanation:

Here, each number is a Number (terminal expression). The Add and Subtract classes combine these numbers and represent non-terminal expressions. They interpret the combined expressions and provide the result. The Client then uses these expressions to interpret and evaluate simple math expressions.

7. When to use?

1. When you need a parser for a simple language or grammar.

2. When performance isn’t a critical concern (interpreters can be slow).

3. When you need a tool that can be easily changed and extended as the grammar evolves.