Digital solutions
Design Patterns avec Laravel

Interpreter Pattern

  • Type : Comportemental
  • Difficulté : 8/10
  • Définition succincte : Le Interpreter Pattern est un design pattern comportemental qui permet de définir la grammaire d'un langage, et d'interpréter des expressions dans ce langage. Il est utilisé pour donner du sens à des instructions spécifiques ou des expressions et les exécuter. Ce pattern est souvent utilisé pour interpréter des langages simples, des formules mathématiques, ou des commandes spécifiques dans un domaine particulier.

Objectif du Interpreter Pattern

L'objectif principal du Interpreter Pattern est de fournir un moyen d'interpréter des expressions dans un domaine spécifique, en suivant une grammaire définie. Ce pattern permet de représenter la structure syntaxique d'un langage dans des objets, et de définir comment chaque expression doit être évaluée. Il est utile pour des moteurs de règles, des analyseurs d'expressions, ou des langages de requêtes spécifiques.

Structure du Interpreter Pattern

  • AbstractExpression : Interface ou classe abstraite qui définit la méthode d'interprétation.
  • TerminalExpression : Implémentation concrète d'une expression qui ne contient pas d'autres expressions (comme des variables ou des constantes).
  • NonTerminalExpression : Implémentation concrète d'une expression qui contient d'autres expressions (comme des opérations).
  • Context : L'environnement qui contient les informations nécessaires à l'interprétation des expressions.

Implémentation avec Laravel

Imaginons que tu développes une application dans Laravel qui doit interpréter des expressions mathématiques saisies par des utilisateurs dans un mini-langage spécifique. Le Interpreter Pattern te permettra de définir des règles pour interpréter et évaluer ces expressions.

a) Définir l'interface Expression (AbstractExpression)

L'interface Expression définit la méthode interpret() qui prend un contexte et évalue l'expression.

// app/Contracts/Expression.php

namespace App\Contracts;

interface Expression
{
    public function interpret(array $context): int;
}

b) Créer des TerminalExpressions

Les TerminalExpressions sont des expressions simples qui ne contiennent pas d'autres expressions, comme des constantes ou des variables.

1. Variable Expression

Cette expression interprète une variable en récupérant sa valeur dans le contexte.

// app/Expressions/VariableExpression.php

namespace App\Expressions;

use App\Contracts\Expression;

class VariableExpression implements Expression
{
    private $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function interpret(array $context): int
    {
        if (!isset($context[$this->name])) {
            throw new \Exception("Variable {$this->name} is not defined.");
        }

        return $context[$this->name];
    }
}
2. Constant Expression

Cette expression interprète une constante numérique.

// app/Expressions/ConstantExpression.php

namespace App\Expressions;

use App\Contracts\Expression;

class ConstantExpression implements Expression
{
    private $value;

    public function __construct(int $value)
    {
        $this->value = $value;
    }

    public function interpret(array $context): int
    {
        return $this->value;
    }
}

c) Créer des NonTerminalExpressions

Les NonTerminalExpressions combinent d'autres expressions pour représenter des opérations plus complexes, comme l'addition ou la multiplication.

1. Addition Expression

Cette expression combine deux sous-expressions et interprète leur somme.

// app/Expressions/AdditionExpression.php

namespace App\Expressions;

use App\Contracts\Expression;

class AdditionExpression implements Expression
{
    private $leftExpression;
    private $rightExpression;

    public function __construct(Expression $leftExpression, Expression $rightExpression)
    {
        $this->leftExpression = $leftExpression;
        $this->rightExpression = $rightExpression;
    }

    public function interpret(array $context): int
    {
        return $this->leftExpression->interpret($context) + $this->rightExpression->interpret($context);
    }
}
2. Multiplication Expression

Cette expression combine deux sous-expressions et interprète leur produit.

// app/Expressions/MultiplicationExpression.php

namespace App\Expressions;

use App\Contracts\Expression;

class MultiplicationExpression implements Expression
{
    private $leftExpression;
    private $rightExpression;

    public function __construct(Expression $leftExpression, Expression $rightExpression)
    {
        $this->leftExpression = $leftExpression;
        $this->rightExpression = $rightExpression;
    }

    public function interpret(array $context): int
    {
        return $this->leftExpression->interpret($context) * $this->rightExpression->interpret($context);
    }
}

d) Utilisation du Interpreter Pattern dans une commande CLI

Nous allons maintenant créer une commande CLI qui interprète des expressions mathématiques définies dynamiquement par l'utilisateur.

1. Commande InterpretExpression

Cette commande simule l'interprétation d'une expression mathématique en utilisant un contexte donné.

// app/Console/Commands/InterpretExpression.php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Expressions\VariableExpression;
use App\Expressions\ConstantExpression;
use App\Expressions\AdditionExpression;
use App\Expressions\MultiplicationExpression;

class InterpretExpression extends Command
{
    protected $signature = 'expression:interpret';
    protected $description = 'Interprète une expression mathématique simple';

    public function handle()
    {
        // Définir un contexte avec des variables
        $context = [
            'x' => 5,
            'y' => 10,
        ];

        // Interpréter l'expression (x + y) * 2
        $x = new VariableExpression('x');
        $y = new VariableExpression('y');
        $constant = new ConstantExpression(2);

        $addition = new AdditionExpression($x, $y); // x + y
        $expression = new MultiplicationExpression($addition, $constant); // (x + y) * 2

        // Exécuter l'interprétation
        $result = $expression->interpret($context);

        // Afficher le résultat
        $this->info("Résultat de l'expression: $result");
    }
}

e) Exécution de la commande

Tu peux maintenant exécuter la commande pour interpréter l'expression (x + y) * 2 avec les valeurs définies dans le contexte.

php artisan expression:interpret

Résultat attendu :

Résultat de l'expression: 30

Avantages du Interpreter Pattern

  1. Flexibilité : Il permet d'ajouter de nouvelles règles ou expressions sans modifier la structure existante.
  2. Modularité : Chaque expression est encapsulée dans une classe séparée, ce qui facilite la maintenance et l'extension du système.
  3. Clarté : Le pattern clarifie la représentation et l'évaluation de la syntaxe d'un langage ou de formules.

Inconvénients du Interpreter Pattern

  1. Complexité accrue : La multiplication des classes pour chaque type d'expression peut rendre le système plus difficile à maintenir dans des contextes simples.
  2. Performances : Ce pattern peut entraîner des problèmes de performance lorsque de nombreuses expressions doivent être évaluées de manière répétée.

Conclusion

Le Interpreter Pattern est particulièrement utile pour créer des moteurs de règles ou des systèmes d'interprétation de langages dans des domaines spécifiques. En Laravel, il peut être utilisé pour analyser et interpréter des règles métier complexes, des formules mathématiques, ou des expressions personnalisées. Ce pattern permet de rendre les règles de syntaxe explicites, modulaires et extensibles, tout en offrant une grande flexibilité dans la gestion de l'interprétation des expressions.