4.3. Interpreter

Maheshmaddi
4 min readApr 10, 2023

--

The Interpreter pattern is a behavioral design pattern that defines a representation for a grammar and provides an interpreter to evaluate expressions based on that grammar. It is particularly useful for designing domain-specific languages, parsing, and interpreting complex expressions or syntax.

The Interpreter pattern is typically used when:

  1. You have a well-defined grammar that needs to be interpreted.
  2. You need to evaluate expressions based on that grammar.
  3. You want to create a domain-specific language or representation for a particular problem.

To implement the Interpreter pattern, follow these steps:

  1. Define an abstract expression class or interface that specifies the common methods for interpreting expressions.
  2. Create concrete expression classes that implement the abstract expression class or interface and represent the different types of expressions in the grammar.
  3. Implement the interpretation method in each concrete expression class, providing the specific evaluation logic for that expression.
  4. In the client code, create an abstract syntax tree of the expressions and invoke the interpretation method on the root node.

Here’s a simple example of the Interpreter pattern in Java:

// Abstract expression
interface Expression {
int interpret();
}

// Terminal expression
class Number implements Expression {
private final int value;

public Number(int value) {
this.value = value;
}

@Override
public int interpret() {
return value;
}
}

// Non-terminal expression
class Add implements Expression {
private final Expression left;
private final Expression right;

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

@Override
public int interpret() {
return left.interpret() + right.interpret();
}
}

// Client code
public class Client {
public static void main(String[] args) {
Expression number1 = new Number(1);
Expression number2 = new Number(2);
Expression addExpression = new Add(number1, number2);

System.out.println(addExpression.interpret()); // Outputs: 3
}
}

In this example, the Expression interface represents the common interface for interpreting expressions. The Number class is a terminal expression that represents a single integer value, while the Add class is a non-terminal expression that represents an addition operation.

Advantages of the Interpreter pattern:

  1. Flexibility: The Interpreter pattern allows for easy extension and modification of the grammar by adding new expression classes.
  2. Clear separation: The pattern separates the interpretation logic from the domain-specific language, making the code more maintainable and easier to understand.

Disadvantages of the Interpreter pattern:

  1. Complexity: The Interpreter pattern can become complex for large or complicated grammars, leading to a large number of expression classes and potentially slow performance.
  2. Limited applicability: The pattern is most suitable for small and simple grammars. For larger grammars, it’s better to use existing parser generators or libraries.

When using the Interpreter pattern, consider its benefits and drawbacks carefully. Use the pattern for small and simple grammars, when you need flexibility in extending the grammar, and when you want a clear separation between the interpretation logic and the domain-specific language. Be aware of the potential complexity and performance issues when dealing with larger or more complicated grammars.

Use Case: Currency Conversion Interpreter

The Interpreter pattern is used to interpret domain-specific languages or to perform tasks based on a specific grammar. In this example, we’ll create a simple currency conversion interpreter that converts values between USD, EUR, and GBP using a given exchange rate.

  1. Create the Expression interface:
public interface Expression {
double interpret(Context context);
}

2. Create the Number class that implements the Expression interface:

public class Number implements Expression {
private final double value;

public Number(double value) {
this.value = value;
}

@Override
public double interpret(Context context) {
return value;
}
}

3. Create the CurrencyConverter class that implements the Expression interface:

public class CurrencyConverter implements Expression {
private final Expression fromCurrency;
private final Expression toCurrency;

public CurrencyConverter(Expression fromCurrency, Expression toCurrency) {
this.fromCurrency = fromCurrency;
this.toCurrency = toCurrency;
}

@Override
public double interpret(Context context) {
double fromValue = fromCurrency.interpret(context);
double toValue = toCurrency.interpret(context);
return fromValue / toValue;
}
}

4. Create the Context class to store exchange rates:

import java.util.HashMap;
import java.util.Map;

public class Context {
private final Map<String, Double> exchangeRates = new HashMap<>();

public void setExchangeRate(String currency, double rate) {
exchangeRates.put(currency, rate);
}

public double getExchangeRate(String currency) {
return exchangeRates.getOrDefault(currency, 1.0);
}
}

5. Create a client to use the currency conversion interpreter:

public class InterpreterPatternDemo {
public static void main(String[] args) {
Context context = new Context();
context.setExchangeRate("USD", 1.0);
context.setExchangeRate("EUR", 0.85);
context.setExchangeRate("GBP", 0.75);

Expression usd100 = new Number(100);
Expression eurToUsd = new CurrencyConverter(new Number(1), new Number(context.getExchangeRate("EUR")));
Expression gbpToUsd = new CurrencyConverter(new Number(1), new Number(context.getExchangeRate("GBP")));

System.out.println("100 USD to EUR: " + usd100.interpret(context) * eurToUsd.interpret(context) + " EUR");
System.out.println("100 USD to GBP: " + usd100.interpret(context) * gbpToUsd.interpret(context) + " GBP");
}
}

The example above demonstrates a simple currency conversion interpreter using the Interpreter pattern. You can extend this to handle more complex expressions and additional currencies as needed.

Note: For complete list of design patterns click here

--

--