Interpreter Pattern
The Interpreter Pattern provides a way to evaluate the syntax or expressions of a language, and it belongs to the behavioral pattern category. This pattern implements an expression interface that interprets a specific context. It is used in SQL parsing, symbol processing engines, etc.
Introduction
Intent: Given a language, define its grammar representation, and define an interpreter that uses this representation to interpret sentences in the language.
Main Solution: To build an interpreter for some fixed grammar to interpret sentences.
When to Use: If a specific type of problem occurs frequently enough, it might be worth representing each instance of the problem as a simple language sentence. This way, an interpreter can be built to solve the problem by interpreting these sentences.
How to Solve: Build a syntax tree and define terminal and non-terminal symbols.
Key Code: Build an environment class that contains some global information, usually a HashMap, outside the interpreter.
Application Examples: Compilers, arithmetic expression calculations.
Advantages:
- Good scalability and flexibility.
- Adds new ways to interpret expressions.
- Easy to implement simple grammars.
Disadvantages:
- Few applicable scenarios.
- Difficult to maintain for complex grammars.
- The interpreter pattern can lead to class bloat.
- The interpreter pattern uses recursive calls.
Usage Scenarios:
- Represent sentences in a language that needs interpretation as an abstract syntax tree.
- Use a simple language to express recurring problems.
- Scenarios where a simple syntax needs interpretation.
Notes: Few applicable scenarios. In Java, consider using expression4J if applicable.
Implementation
We will create an interface Expression and implement it in concrete classes. Define the TerminalExpression class as the main interpreter in the context. Other classes OrExpression, AndExpression are used to create composite expressions.
InterpreterPatternDemo, our demo class, uses Expression classes to create rules and demonstrate expression parsing.
Step 1
Create an expression interface.
Expression.java
public interface Expression {
public boolean interpret(String context);
}
Step 2
Create concrete classes implementing the above interface.
TerminalExpression.java
public class TerminalExpression implements Expression {
private String data;
public TerminalExpression(String data){
this.data = data;
}
@Override
public boolean interpret(String context) {
if(context.contains(data)){
return true;
}
return false;
}
}
OrExpression.java
public class OrExpression implements Expression {
private Expression expr1 = null;
private Expression expr2 = null;
public OrExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
@Override
public boolean interpret(String context) {
return expr1.interpret(context) || expr2.interpret(context);
}
}
AndExpression.java
public class AndExpression implements Expression {
private Expression expr1 = null;
private Expression expr2 = null;
public AndExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
@Override
public boolean interpret(String context) {
return expr1.interpret(context) && expr2.interpret(context);
}
}
Step 3
InterpreterPatternDemo uses Expression classes to create rules and parse them.
InterpreterPatternDemo.java
public class InterpreterPatternDemo {
// Rule: Robert and John are male
public static Expression getMaleExpression(){
Expression robert = new TerminalExpression("Robert");
Expression john = new TerminalExpression("John");
return new OrExpression(robert, john);
}
// Rule: Julie is a married woman
public static Expression getMarriedWomanExpression(){
Expression julie = new TerminalExpression("Julie");
Expression married = new TerminalExpression("Married");
return new AndExpression(julie, married);
}
public static void main(String[] args) {
Expression isMale = getMaleExpression();
Expression isMarriedWoman = getMarriedWomanExpression();
System.out.println("John is male? " + isMale.interpret("John"));
System.out.println("Julie is a married woman? "
+ isMarriedWoman.interpret("Married Julie"));
}
}
Step 4
Execute the program, output results:
John is male? true
Julie is a married woman? true