Interpreter Pattern – interpretarea și execuția expresiilor
În aplicațiile software apar frecvent situații în care trebuie să interpretăm un limbaj simplu, o expresie sau un set de reguli: filtre, formule matematice, reguli de validare, expresii de căutare sau chiar DSL-uri (Domain Specific Languages). Interpreter Pattern este un design pattern comportamental care oferă o soluție elegantă pentru astfel de scenarii.
În acest articol vom vedea ce este Interpreter Pattern, când se folosește, avantaje și limitări, precum și un exemplu clar în C# (.NET).
Ce este Interpreter Pattern?
Interpreter Pattern definește o reprezentare pentru gramatica unui limbaj și un mecanism care permite interpretarea expresiilor din acel limbaj. Fiecare regulă din gramatică este reprezentată printr-o clasă, iar evaluarea expresiei se face prin compunerea acestor obiecte.
Cu alte cuvinte, în loc să scrii un parser complex într-o singură clasă, împarți regulile limbajului în obiecte mici și reutilizabile.
📌 Ideea de bază:
“O expresie este un obiect care știe să se interpreteze singur.”
Când este util Interpreter Pattern?
Interpreter Pattern este potrivit atunci când:
-
Ai un limbaj simplu, cu reguli bine definite
-
Expresiile sunt relativ stabile, dar pot fi combinate
-
Ai nevoie de evaluare dinamică (la runtime)
-
Vrei să eviți if / else sau switch foarte complexe
-
Construiești un DSL pentru un domeniu specific
Exemple reale:
-
Expresii matematice (1 + 2 - 3)
-
Reguli de business (age > 18 AND country == "RO")
-
Filtre de căutare
-
Motoare de reguli
-
Expresii logice pentru permisiuni
Structura pattern-ului
Interpreter Pattern conține câteva elemente cheie:
-
Expression (Abstract Expression) – interfața comună
-
TerminalExpression – expresii finale (valori concrete)
-
NonTerminalExpression – expresii compuse (operații)
-
Context – informațiile necesare interpretării
Exemplu practic în C# (.NET)
Să implementăm un interpreter simplu pentru expresii matematice.
1️⃣ Interfața Expression
public interface IExpression
{
int Interpret();
}
2️⃣ TerminalExpression – valori concrete
public class NumberExpression : IExpression
{
private readonly int _number;
public NumberExpression(int number)
{
_number = number;
}
public int Interpret()
{
return _number;
}
}
3️⃣ NonTerminalExpression – operații
Adunare
public class AddExpression : IExpression
{
private readonly IExpression _left;
private readonly IExpression _right;
public AddExpression(IExpression left, IExpression right)
{
_left = left;
_right = right;
}
public int Interpret()
{
return _left.Interpret() + _right.Interpret();
}
}
Scădere
public class SubtractExpression : IExpression
{
private readonly IExpression _left;
private readonly IExpression _right;
public SubtractExpression(IExpression left, IExpression right)
{
_left = left;
_right = right;
}
public int Interpret()
{
return _left.Interpret() - _right.Interpret();
}
}
4️⃣ Utilizarea interpreterului
class Program
{
static void Main()
{
// (5 + 3) - 2
IExpression expression = new SubtractExpression(
new AddExpression(
new NumberExpression(5),
new NumberExpression(3)
),
new NumberExpression(2)
);
Console.WriteLine(expression.Interpret()); // Output: 6
}
}
✔️ Fiecare expresie știe să se interpreteze
✔️ Compoziția este flexibilă
✔️ Codul este extensibil
Avantaje
✅ Cod clar și structurat
✅ Ușor de extins cu noi reguli
✅ Elimină logica complexă dintr-o singură clasă
✅ Se pot construi expresii dinamice la runtime
Dezavantaje
⚠️ Număr mare de clase pentru gramatici complexe
⚠️ Performanță mai slabă pentru expresii foarte mari
⚠️ Nu este potrivit pentru limbaje complexe (SQL, JSON etc.)
👉 Pentru cazuri avansate, parser-ele dedicate sunt o soluție mai bună.
Interpreter Pattern în .NET real
În ecosistemul .NET, pattern-ul apare implicit în:
-
Motoare de reguli
-
Framework-uri de validare
-
Sisteme de filtrare
-
Expresii LINQ (conceptual)
De multe ori îl folosești fără să-ți dai seama, sub forma unor expresii compuse.
Concluzie
Interpreter Pattern este o soluție elegantă pentru interpretarea expresiilor și regulilor într-un mod extensibil și clar. Nu este un pattern universal, dar atunci când este folosit corect, reduce complexitatea și crește lizibilitatea codului.