Interpreter
Defines a grammar for a language and an interpreter to interpret sentences in that language.
Think of it as a way to process a sequence of words or symbols according to a set of rules, like evaluating a math equation or parsing a search query.
classDiagram
class AbstractExpression {
<<interface>>
+interpret(context)
}
class TerminalExpression {
+interpret(context)
}
class NonterminalExpression {
+interpret(context)
}
class Context {
}
AbstractExpression <|-- TerminalExpression
AbstractExpression <|-- NonterminalExpression
NonterminalExpression o-- AbstractExpression
Client --> AbstractExpression
Client --> Context
When to use
Use the Interpreter pattern when:
- You have a simple language to interpret.
- The grammar of the language is simple and stable.
- Efficiency is not a critical concern.
Explanation
Problem
You need to process and evaluate expressions in a specific language (like “x + y - z” or “show users where age > 20”). Writing a massive parser with endless if/else or regex checks is hard to maintain and extend.
Solution
The Interpreter pattern suggests turning each grammar rule into a class.
- Terminal Expressions: Basic elements (like numbers or variable names).
- Non-terminal Expressions: Combinations of other expressions (like “Add”, “Subtract”).
You build a tree of these objects (Syntax Tree) and call
interpret()on the root.
Real world problem
- Music Notation: Musicians read symbols (notes, rests) and “interpret” them into sound.
- Calculator: Entering “5 + 10” is interpreted by the calculator logic to produce “15”.
- SQL: Database engines interpret SQL queries to fetch data.
Pros and Cons
| Pros | Cons |
|---|---|
Comparison
- Composite: The Interpreter’s syntax tree is often an instance of the Composite pattern.
- Visitor: You can put the
interpretlogic into a Visitor to avoid modifying the expression classes. - Flyweight: Useful for sharing terminal symbols to save memory.
Code example
Typescript
Php