DEV Community

Cover image for Interpreter Pattern: dare un linguaggio al tuo dominio
Dev-Iadicola
Dev-Iadicola

Posted on • Originally published at iadicola.it

Interpreter Pattern: dare un linguaggio al tuo dominio

Il problema: logica configurabile che non può vivere nel codice

Un sistema di sconti ha regole che cambiano ogni settimana: "se il carrello supera 100 EUR e il cliente e premium, applica il 15%". "Se e Black Friday e la categoria e elettronica, applica il 25%". Hardcodare queste regole nel PHP significa deploy per ogni cambio. Metterle in un database come stringhe opache non basta — servono condizioni composte con AND, OR, confronti e variabili.

L'Interpreter Pattern propone di definire un piccolo linguaggio formale per esprimere queste regole e costruire un interprete che le esegue a runtime. La regola diventa un'espressione strutturata: AND(GT(cart.total, 100), EQ(customer.tier, "premium")). L'interprete attraversa questa struttura e la valuta nel contesto corrente.

Cos'e l'Interpreter Pattern: definizione formale

Il Gang of Four definisce l'Interpreter come un pattern comportamentale che "dato un linguaggio, definisce una rappresentazione per la sua grammatica insieme a un interprete che usa la rappresentazione per interpretare frasi nel linguaggio". La struttura:

  • AbstractExpression: interfaccia con interpret(Context $ctx): mixed
  • TerminalExpression: espressioni foglia che non contengono sotto-espressioni (variabili, costanti)
  • NonterminalExpression: espressioni composte che contengono sotto-espressioni (AND, OR, GT, EQ)
  • Context: contiene le variabili e i valori disponibili durante l'interpretazione

Esempio teorico: un motore di regole per sconti

Definiamo le espressioni del nostro mini-linguaggio:

  • VariableExpression('cart.total'): legge il valore dal contesto. Terminal expression.
  • LiteralExpression(100): restituisce un valore costante. Terminal expression.
  • GreaterThanExpression($left, $right): valuta $left->interpret($ctx) > $right->interpret($ctx). Nonterminal.
  • EqualsExpression($left, $right): confronto di uguaglianza. Nonterminal.
  • AndExpression($left, $right): entrambe le sotto-espressioni devono essere true. Nonterminal.
  • OrExpression($left, $right): almeno una deve essere true. Nonterminal.
  • NotExpression($expr): nega il risultato. Nonterminal.

La regola "carrello > 100 AND cliente premium" diventa: new AndExpression(new GreaterThanExpression(new VariableExpression('cart.total'), new LiteralExpression(100)), new EqualsExpression(new VariableExpression('customer.tier'), new LiteralExpression('premium'))).

Chiamare $rule->interpret($context) restituisce true o false. Il contesto contiene ['cart.total' => 150, 'customer.tier' => 'premium']. La regola si valuta ricorsivamente senza un singolo if nel codice dell'interprete.

Esempio teorico: query language per filtri

Un'API REST offre filtri complessi: ?filter=status:active AND (category:electronics OR category:books) AND price:>50. Invece di parsare questa stringa con regex fragili, la trasformi in un albero di espressioni e la interpreti contro ogni record del database. L'Interpreter Pattern rende il parsing strutturato e la valutazione ricorsiva, pulita e testabile.

Interpreter e il Composite Pattern

L'Interpreter Pattern e strettamente legato al Composite Pattern: le espressioni formano un albero dove le nonterminal expression sono compositi e le terminal expression sono foglie. Il metodo interpret() attraversa l'albero ricorsivamente, esattamente come getTotal() attraversa l'albero di un preventivo nel Composite. La differenza e l'intento: il Composite modella strutture parte-intero, l'Interpreter modella grammatiche e le valuta.

Limiti e alternative

L'Interpreter Pattern funziona bene per linguaggi semplici con grammatiche piccole. Per linguaggi complessi (SQL, template engine, linguaggi di programmazione), l'albero di espressioni diventa ingestibile e servono tool specializzati: parser generator (ANTLR), PEG parser, o AST visitor combinati con l'Interpreter.

  • Grammatiche con meno di 20 regole: Interpreter Pattern funziona bene
  • Grammatiche con 20-50 regole: valuta se un parser generator e più manutenibile
  • Grammatiche con 50+ regole: usa un parser generator o un framework dedicato

Quando usare l'Interpreter Pattern

  • Usa l'Interpreter quando il dominio ha regole configurabili che cambiano frequentemente
  • Usa l'Interpreter quando vuoi un mini-linguaggio per esprimere logica di business senza deploy
  • Usa l'Interpreter quando la grammatica e semplice e le espressioni formano naturalmente un albero
  • Non usare l'Interpreter per linguaggi complessi: il pattern non scala bene oltre una certa complessità
  • Non usare l'Interpreter se le regole non cambiano mai: hardcodarle nel PHP e più semplice e performante

L'Interpreter Pattern e il pattern del linguaggio incorporato: dai al tuo dominio la capacità di esprimersi in una grammatica formale. E un pattern di nicchia ma potente: quando serve, niente altro lo sostituisce. Motori di regole, filtri configurabili, validatori dinamici — tutti beneficiano di un piccolo interprete ben progettato.


👉 Leggi l'articolo completo su iadicola.it

Top comments (0)