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
  • Easy to change and extend grammar.
  • Inefficient regarding performance.
  • Implementing grammar is straightforward.
  • Complex grammars become hard to manage.
  • Comparison

    • Composite: The Interpreter’s syntax tree is often an instance of the Composite pattern.
    • Visitor: You can put the interpret logic into a Visitor to avoid modifying the expression classes.
    • Flyweight: Useful for sharing terminal symbols to save memory.

    Code example

    Typescript

    Php