Skip to content

Commit 7eb2af0

Browse files
Interpreter Pattern Docs Added
1 parent 8b00bca commit 7eb2af0

4 files changed

Lines changed: 284 additions & 2 deletions

File tree

content/Best Practices.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,8 @@ Finally, remember that **design patterns are guidelines, not strict rules**. Rea
8888

8989
- [[Flyweight Pattern]] :
9090
**Trigger clue:** “Large number of similar objects”.
91-
**Core idea:** Share common data between multiple objects to reduce memory usage instead of storing duplicate data in each object.
91+
**Core idea:** Share common data between multiple objects to reduce memory usage instead of storing duplicate data in each object.
92+
93+
- [[Interpreter Pattern]] :
94+
**Trigger clue:** “Evaluate expressions”, “Custom language or grammar”, “Expression tree”
95+
**Core idea:** Represent a language’s grammar as classes and interpret expressions by evaluating them recursively.

content/Glossary.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,7 @@ The **Builder Pattern** is a creational design pattern that constructs complex o
4040
**Chain of Responsibility (CoR) Pattern** is a behavioral design pattern where a request is passed through a chain of handlers, and each handler decides whether to process it or pass it to the next handler.
4141
### 18. Flyweight Pattern
4242
The **Flyweight Pattern** is a structural design pattern that reduces memory usage by sharing common data between multiple objects instead of storing duplicate data in each object. It separates shared data from unique data, allowing efficient handling of large numbers of similar objects.
43+
### 19. Interpreter Pattern
44+
The **Interpreter Pattern** is a behavioral design pattern that represents a language’s grammar as classes and interprets expressions using those classes.
4345

4446
_more Coming soon_

content/Interpreter Pattern.md

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
---
2+
title: Interpreter Pattern
3+
created: 2026-04-25
4+
tags:
5+
- behavioral
6+
---
7+
## Definition
8+
9+
The **Interpreter Pattern** is a behavioral design pattern that defines a representation for a language’s grammar and provides an interpreter to evaluate sentences in that language.
10+
11+
---
12+
## Real World Analogy
13+
14+
Imagine you want to create a very small custom language for a specific task. For example, you define simple instructions like assigning values to variables, performing addition, and printing results.
15+
16+
Before executing such a language, you must first define how its grammar looks. That means deciding what kind of expressions are allowed, how variables behave, and how operations like addition work.
17+
18+
In real programming languages, this is usually handled by a parser, which is a complex component. In this example, we skip building a full parser and directly construct the expressions using code.
19+
20+
Here is the small language we are interpreting:
21+
```txt
22+
X=10
23+
Y=10
24+
Z=X+Y
25+
PRINT Z
26+
```
27+
This language includes:
28+
- Assignment of values
29+
- Variables
30+
- Addition operation
31+
- Print operation
32+
Using the **Interpreter Pattern**, we represent each of these rules as classes and then evaluate them.
33+
34+
---
35+
## Key Concepts
36+
37+
**Terminal Expression**
38+
Terminal expressions are the simplest elements of the language. They do not contain other expressions. Examples include numbers and variables.
39+
40+
**Non-Terminal Expression**
41+
Non-terminal expressions are composed of other expressions. They represent operations such as addition, subtraction, or more complex rules.
42+
43+
---
44+
## Design
45+
46+
```mermaid
47+
classDiagram
48+
direction LR
49+
50+
class Context {
51+
- Map<String, Integer> variables
52+
+ set(String name, int value)
53+
+ get(String name) int
54+
}
55+
56+
class Expression {
57+
<<interface>>
58+
+ interpret(Context context) int
59+
}
60+
61+
class NumberExpression {
62+
- int value
63+
+ interpret(Context context) int
64+
}
65+
66+
class VariableExpression {
67+
- String name
68+
+ interpret(Context context) int
69+
}
70+
71+
class AddExpression {
72+
- Expression left
73+
- Expression right
74+
+ interpret(Context context) int
75+
}
76+
77+
class Statement {
78+
<<interface>>
79+
+ execute(Context context)
80+
}
81+
82+
class AssignmentStatement {
83+
- String variable
84+
- Expression expression
85+
+ execute(Context context)
86+
}
87+
88+
class PrintStatement {
89+
- Expression expression
90+
+ execute(Context context)
91+
}
92+
93+
%% Relationships
94+
Expression <|.. NumberExpression
95+
Expression <|.. VariableExpression
96+
Expression <|.. AddExpression
97+
98+
Statement <|.. AssignmentStatement
99+
Statement <|.. PrintStatement
100+
101+
AddExpression --> Expression
102+
AssignmentStatement --> Expression
103+
AssignmentStatement --> Context
104+
105+
PrintStatement --> Expression
106+
PrintStatement --> Context
107+
108+
VariableExpression --> Context
109+
```
110+
_Class Diagram of the Interpreter Design Pattern_
111+
112+
---
113+
## Implementation in Java
114+
115+
```java title="Context.java"
116+
import java.util.HashMap;
117+
import java.util.Map;
118+
119+
class Context {
120+
private final Map<String, Integer> variables = new HashMap<>();
121+
122+
public void set(String name, int value) {
123+
this.variables.put(name, value);
124+
}
125+
126+
public int get(String name) {
127+
if (!variables.containsKey(name)) {
128+
throw new RuntimeException("Variable not Defined " + name);
129+
}
130+
return variables.get(name);
131+
}
132+
}
133+
```
134+
The Context class acts as memory. It stores variable names and their values. Every expression uses this shared context to read or write values.
135+
136+
```java title="Expression.java"
137+
interface Expression {
138+
int interpret(Context context);
139+
}
140+
```
141+
This interface defines a common method for all expressions. Every expression must know how to interpret itself using the context.
142+
143+
```java title="NumberExpression.java"
144+
class NumberExpression implements Expression {
145+
private final int value;
146+
147+
public NumberExpression(int value) {
148+
this.value = value;
149+
}
150+
151+
public int interpret(Context context) {
152+
return value;
153+
}
154+
}
155+
```
156+
This is a terminal expression. It simply returns a constant number.
157+
158+
```java title="VariableExpression.java"
159+
class VariableExpression implements Expression {
160+
private final String name;
161+
162+
public VariableExpression(String name) {
163+
this.name = name;
164+
}
165+
166+
public int interpret(Context context) {
167+
return context.get(name);
168+
}
169+
}
170+
```
171+
This is also a terminal expression. It retrieves the value of a variable from the context.
172+
173+
```java title="AddExpression.java"
174+
class AddExpression implements Expression {
175+
private final Expression left, right;
176+
177+
public AddExpression(Expression left, Expression right) {
178+
this.left = left;
179+
this.right = right;
180+
}
181+
182+
public int interpret(Context context) {
183+
return left.interpret(context) + right.interpret(context);
184+
}
185+
}
186+
```
187+
This is a non-terminal expression. It combines two expressions and returns their sum.
188+
189+
```java title="Statement.java"
190+
interface Statement {
191+
void execute(Context context);
192+
}
193+
```
194+
Statements represent actions instead of values. They execute logic using the context.
195+
196+
```java title="AssignmentStatement.java"
197+
class AssignmentStatement implements Statement {
198+
private final String variable;
199+
private final Expression expression;
200+
201+
public AssignmentStatement(String variable, Expression expression) {
202+
this.variable = variable;
203+
this.expression = expression;
204+
}
205+
206+
public void execute(Context context) {
207+
int value = expression.interpret(context);
208+
context.set(variable, value);
209+
}
210+
}
211+
```
212+
This statement evaluates an expression and stores the result in the context under a variable name.
213+
214+
```java title="PrintStatement.java"
215+
class PrintStatement implements Statement {
216+
private final Expression expression;
217+
218+
public PrintStatement(Expression expression) {
219+
this.expression = expression;
220+
}
221+
222+
public void execute(Context context) {
223+
System.out.println(expression.interpret(context));
224+
}
225+
}
226+
```
227+
This statement evaluates an expression and prints the result.
228+
229+
```java title="InterpreterPattern.java"
230+
public static void main(String[] args) {
231+
Context context = new Context();
232+
233+
Statement[] statements = {
234+
new AssignmentStatement("X", new NumberExpression(2)),
235+
new AssignmentStatement("Y", new NumberExpression(3)),
236+
new AssignmentStatement("Z", new AddExpression(
237+
new VariableExpression("X"),
238+
new VariableExpression("Y")
239+
)),
240+
new PrintStatement(new VariableExpression("Z"))
241+
};
242+
243+
for (Statement st : statements) {
244+
st.execute(context);
245+
}
246+
}
247+
```
248+
Here we manually construct the language using objects. Each statement represents one line of our custom language. When executed in sequence, they simulate interpreting the language.
249+
250+
**Output**:
251+
```bash
252+
5
253+
```
254+
255+
---
256+
## Real World Examples
257+
258+
- Expression evaluators such as calculators where inputs like "2 + 3" are evaluated
259+
- SQL-like query processing where conditions are interpreted step by step
260+
- Simple rule engines where conditions and actions are defined as expressions
261+
262+
These examples follow the same idea of breaking a language into smaller parts and interpreting them using objects.
263+
264+
---
265+
## Design Principles:
266+
267+
- **Encapsulate What Varies** - Identify the parts of the code that are going to change and encapsulate them into separate class just like the Strategy Pattern.
268+
- **Favor Composition Over Inheritance** - Instead of using inheritance on extending functionality, rather use composition by delegating behavior to other objects.
269+
- **Program to Interface not Implementations** - Write code that depends on Abstractions or Interfaces rather than Concrete Classes.
270+
- **Strive for Loosely coupled design between objects that interact** - When implementing a class, avoid tightly coupled classes. Instead, use loosely coupled objects by leveraging abstractions and interfaces. This approach ensures that the class does not heavily depend on other classes.
271+
- **Classes Should be Open for Extension But closed for Modification** - Design your classes so you can extend their behavior without altering their existing, stable code.
272+
- **Depend on Abstractions, Do not depend on concrete class** - Rely on interfaces or abstract types instead of concrete classes so you can swap implementations without altering client code.
273+
- **Talk Only To Your Friends** - An object may only call methods on itself, its direct components, parameters passed in, or objects it creates.
274+
- **Don't call us, we'll call you** - This means the framework controls the flow of execution, not the user’s code (Inversion of Control).
275+
- **A class should have only one reason to change** - This emphasizes the Single Responsibility Principle, ensuring each class focuses on just one functionality.

content/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ Consider an `SQLManager` class that performs CRUD operations. It has an `ILogger
144144
19. [[Builder Pattern]]
145145
20. [[Chain of Responsibility Pattern]]
146146
21. [[Flyweight Pattern]]
147-
22. [[Glossary]]
147+
22. [[Interpreter Pattern]]
148+
23. [[Glossary]]
148149

149150
---
150151
> [!Note]

0 commit comments

Comments
 (0)