Card 01/ 08
Interpreter Pattern: Representing a Small Language as a Tree of Classes
Each grammar rule becomes a class, and a sentence becomes a tree you can evaluate.
The Interpreter pattern represents a small language as classes, one for each rule of its grammar, so that a sentence in the language becomes a tree of objects, and evaluating the tree evaluates the sentence. A grammar is the set of rules saying which sentences a language allows, such as "a rule is a condition, or two rules joined by and". This card covers the problem that calls for it, the intent, and when it fits.
The problem is a rule language handled as text. A shop lets its staff write discount rules such as total > 100 and member. Splitting the string on and and checking each half works until someone writes member and (total > 100 or code = SPRING), and the brackets, the order of and and or, and a not each need another special case in the string handling.
Without the patternthe rule is cut up as text
def applies(rule, basket):
for part in rule.split(" and "):
if part == "member" and not basket.member:
return False
if part.startswith("total > "):
...
return TrueBrackets and or need new branches here.
With the patternthe rule is a tree of objects
rule = And(IsMember(),
Or(TotalOver(100), CodeIs("SPRING")))
rule.interpret(basket)Each class evaluates one rule; nesting is the tree.
The Gang of Four state the intent as: given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language. The representation is the classes; the interpreter is a method, usually called interpret, that each class implements.
Interpreter is one of eleven behavioural patterns, the family concerned with which object does which part of the work, and how objects communicate.
| Pattern | What it does |
|---|---|
| Chain of Responsibility | Passes a request along a chain of handlers until one handles it. |
| Command | Turns a request into an object that can be stored, queued or undone. |
| Interpreter (this topic) | Represents a small language's grammar as classes and evaluates its sentences. |
| Iterator | Visits the elements of a collection without exposing how it is stored. |
| Mediator | Routes the communication between objects through one central object. |
| Memento | Captures an object's state so it can be restored later. |
| Observer | Notifies many objects when one object changes. |
| State | Changes an object's behaviour when its internal state changes. |
| Strategy | Swaps one algorithm for another behind a common interface. |
| Template Method | Fixes an algorithm's steps in a base class and lets subclasses fill some in. |
| Visitor | Adds operations to a class hierarchy without changing its classes. |
Use it when
- A small language recurs in the program, such as rules, filters or formulas that users or configuration supply.
- The grammar is small, with a handful of rules, and stays stable.
- Speed of evaluation matters less than being able to read and extend the rules.
Avoid it when
- The grammar is large, where a class per rule becomes hundreds of classes and a parser generator serves better.
- Evaluation must be fast, where compiling the sentence to another form beats walking a tree.
- An existing language already does the job, such as SQL, a regular expression, or JSON with a schema.
← → move through sections and cards