Interpreter Pattern

📢 This article was translated by gemini-2.5-flash

Interpreter Pattern: Class Behavioral Pattern

Intent

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

Structure

Interpreter Pattern

Here’s the breakdown:

  • AbstractExpression: Declares an Interpret operation, shared by all nodes in the abstract syntax tree.
  • TerminalExpression: Implements the Interpret operation associated with terminal symbols in the grammar. Each terminal symbol in a sentence needs an instance of this class.
  • NonterminalExpression: There’s one for each rule in the grammar. It maintains an AbstractExpression instance variable for each symbol and implements the Interpret operation for nonterminal symbols.
  • Context: Holds global information outside the interpreter.
  • Client: Builds (or is given) the abstract syntax tree representing a specific sentence in the language defined by the grammar. This tree is composed of NonterminalExpression and TerminalExpression instances. It then invokes the Interpret operation.

When to Use It

The Interpreter pattern shines when you need to interpret a language, and sentences in that language can be represented as an abstract syntax tree. It works best if:

  • The grammar is simple.
  • Efficiency isn’t a critical concern.

Example

Checking a string: “someone of ? region” (e.g., ‘developer of A region’).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import java.util.*;

public class InterpreterPattern {
    public static void main(String[] args) {
        Context context = new Context();

        context.check("developer of A region");
    }
}

class Context{
    private String[] regions = {"A region", "B region", "C region"};
    private String[] persons = {"developer", "tester"};

    private NonterminalExpression nte;

    public Context(){
         TerminalExpression region = new TerminalExpression(regions);
         TerminalExpression person = new TerminalExpression(persons);
         nte = new NonterminalExpression(region, person);
    }

    public void check(String info){
        boolean bool = nte.Interpret(info);
        if(bool){
            System.out.println("right");
        }else {
            System.out.println("wrong");
        }
    }
}

interface Expression{
    public boolean Interpret(String info);
}

class NonterminalExpression implements Expression{
    TerminalExpression region;
    TerminalExpression person;
    public NonterminalExpression(TerminalExpression region, TerminalExpression person){
        this.person = person;
        this.region = region;
    }

    @Override
    public boolean Interpret(String info){
        String[] str = info.split(" of ");
        // "developer of A region" --> str = {"developer", "A region"}
        return region.Interpret(str[1]) && person.Interpret(str[0]);
    }
}

class TerminalExpression implements Expression{
    private Set<String> set = new HashSet<>();

    public TerminalExpression(String[] data){
        for(String str : data){
            set.add(str);
        }
    }

    @Override
    public boolean Interpret(String info){
        return set.contains(info);
    }
}