Cover of Design Patterns by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides - Business and Economics Book

From "Design Patterns"

Author: Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides
Publisher: Pearson Education
Year: 1994
Category: Computers

🎧 Free Preview Complete

You've listened to your free 10-minute preview.
Sign up free to continue listening to the full summary.

🎧 Listen to Summary

Free 10-min Preview
0:00
Speed:
10:00 free remaining
Chapter 5: Behavioral Patterns
Key Insight 3 from this chapter

Interpreter Pattern

Key Insight

The Interpreter pattern defines a representation for a language's grammar and an interpreter that uses this representation to interpret sentences in that language. This pattern is valuable when a particular type of problem frequently occurs, making it worthwhile to express problem instances as sentences in a simple language. An interpreter then solves these problems by interpreting these sentences. A common example is string pattern matching, where regular expressions define patterns. Rather than creating custom matching algorithms for each pattern, a search algorithm can interpret a regular expression. The pattern outlines how to define a grammar, represent sentences as abstract syntax trees (ASTs), and interpret them. For regular expressions, this means defining a grammar (e.g., with `expression` as a start symbol and `literal` as a terminal symbol), representing a specific regular expression (like 'raining & (dogs | cats) *') as an AST, and interpreting that AST. The grammar rules are typically represented by classes, with symbols on the right-hand side of rules becoming instance variables, forming a class hierarchy like `RegularExpression` with subclasses such as `LiteralExpression`, `AlternationExpression`, `SequenceExpression`, and `RepetitionExpression`.

Interpretation is achieved by defining an `Interpret` operation on each `AbstractExpression` subclass. This operation takes a context (e.g., input string, match progress) as an argument. Each subclass implements `Interpret` to match its part of the input string based on the current context. For instance, `LiteralExpression` checks if the input matches its defined literal, `AlternationExpression` checks for a match with any of its alternatives, and `RepetitionExpression` checks for multiple occurrences of its encapsulated expression. The Interpreter pattern is most effective when the grammar is simple; for complex grammars, the resulting class hierarchy can become large and unmanageable, making tools like parser generators a more appropriate alternative, as they can interpret expressions without necessarily building ASTs, potentially saving space and time. Furthermore, the pattern works best when efficiency is not a critical concern, since highly optimized interpreters often translate parse trees into alternative forms (like state machines for regular expressions) before actual execution, though the translator itself could still use the Interpreter pattern.

The structure of the Interpreter pattern involves `AbstractExpression` (declaring the `Interpret` operation), `TerminalExpression` (implementing `Interpret` for terminal grammar symbols), `NonterminalExpression` (one for each grammar rule, maintaining `AbstractExpression` instance variables for sub-symbols, and recursively calling `Interpret` on them), `Context` (holding global interpreter information), and `Client` (which builds or is given the abstract syntax tree, initializes the context, and invokes the `Interpret` operation). The client builds the sentence as an AST from `NonterminalExpression` and `TerminalExpression` instances, initializes the context, and initiates the interpretation. Each `NonterminalExpression` node defines `Interpret` in terms of its subexpressions, with `TerminalExpression` nodes forming the base cases of the recursion. `Interpret` operations utilize the context to manage the interpreter's state. Benefits include ease of changing and extending the grammar through inheritance, and straightforward implementation of grammar rules. However, complex grammars are hard to maintain due to the large number of classes required. The pattern also facilitates adding new ways to interpret expressions, such as pretty-printing or type-checking; however, if many new interpretation methods are consistently added, the `Visitor` pattern is a better choice to avoid modifying the grammar classes repeatedly. This pattern shares many implementation issues with the `Composite` pattern.

📚 Continue Your Learning Journey — No Payment Required

Access the complete Design Patterns summary with audio narration, key takeaways, and actionable insights from Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides.