Digital solutions
Design Patterns avec Laravel

Composite Pattern

  • Type : Structurel
  • Difficulté : 6/10
  • Définition succincte : Le Composite Pattern est un design pattern structurel qui permet de traiter des objets individuels et des groupes d'objets de manière uniforme. Ce pattern est particulièrement utile pour représenter des structures hiérarchiques telles que des arbres où chaque composant peut être un objet simple ou un ensemble d'objets. Il permet de manipuler des collections d'objets comme s'ils étaient des objets individuels.

Objectif du Composite Pattern

Le Composite Pattern permet de compositer des objets en une structure arborescente où chaque composant peut être un feuille (objet simple) ou un composite (ensemble d'objets). Il unifie l'accès et le traitement de ces composants sans se soucier de leur niveau de complexité. Ce pattern est utile lorsqu'une partie de ton application doit gérer des structures hiérarchiques.

Structure du Composite Pattern

  • Component : Interface ou classe abstraite qui définit les opérations communes aux objets individuels et aux composites.
  • Leaf : Un composant simple qui n'a pas de sous-composants.
  • Composite : Un composant complexe qui peut contenir d'autres composants (y compris des feuilles et d'autres composites).
  • Client : L'objet qui interagit avec la structure composite de manière unifiée.

Implémentation avec Laravel

Prenons un exemple dans une application Laravel où tu gères une structure hiérarchique de fichiers et dossiers. Chaque dossier peut contenir des fichiers ou d'autres dossiers, et tu souhaites parcourir cette structure de manière récursive pour lister son contenu.

a) Créer l'interface Component

L'interface Component définit les opérations communes à la fois aux fichiers et aux dossiers, comme l'affichage du contenu.

// app/Contracts/Component.php

namespace App\Contracts;

interface Component
{
    public function display(): string;
}

b) Créer la classe Leaf File

Les fichiers sont des objets simples qui n'ont pas de sous-composants. Ils implémentent directement l'interface Component.

// app/Models/File.php

namespace App\Models;

use App\Contracts\Component;

class File implements Component
{
    private $name;

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

    public function display(): string
    {
        return "File: " . $this->name;
    }
}

c) Créer la classe Composite Folder

Les dossiers peuvent contenir d'autres composants, qu'ils soient des fichiers ou d'autres dossiers. Ils doivent être capables de gérer récursivement les composants qu'ils contiennent.

// app/Models/Folder.php

namespace App\Models;

use App\Contracts\Component;

class Folder implements Component
{
    private $name;
    private $components = [];

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

    // Ajouter un fichier ou un dossier au dossier
    public function add(Component $component): void
    {
        $this->components[] = $component;
    }

    // Afficher le contenu du dossier
    public function display(): string
    {
        $output = "Folder: " . $this->name . "\n";

        foreach ($this->components as $component) {
            $output .= '  ' . $component->display() . "\n";
        }

        return $output;
    }
}

d) Utilisation du Composite Pattern dans une commande CLI

Nous allons maintenant créer une commande CLI qui simule l'ajout de fichiers et dossiers dans une structure et les affiche récursivement.

1. Commande DisplayFileStructure

Cette commande construit une structure composite de dossiers et de fichiers et affiche leur contenu.

// app/Console/Commands/DisplayFileStructure.php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Models\File;
use App\Models\Folder;

class DisplayFileStructure extends Command
{
    protected $signature = 'files:display';
    protected $description = 'Affiche la structure des fichiers et des dossiers en utilisant le Composite Pattern';

    public function handle()
    {
        // Créer des fichiers
        $file1 = new File('file1.txt');
        $file2 = new File('file2.txt');
        $file3 = new File('file3.txt');

        // Créer des dossiers
        $folder1 = new Folder('Documents');
        $folder2 = new Folder('Images');

        // Ajouter des fichiers au dossier Documents
        $folder1->add($file1);
        $folder1->add($file2);

        // Ajouter des fichiers et des dossiers dans Images
        $folder2->add($file3);
        $folder2->add($folder1);

        // Afficher la structure
        $this->info($folder2->display());
    }
}

e) Exécution de la commande

Tu peux maintenant exécuter la commande pour afficher la structure des fichiers et dossiers.

php artisan files:display

Résultat attendu :

Folder: Images
  File: file3.txt
  Folder: Documents
    File: file1.txt
    File: file2.txt

Avantages du Composite Pattern

  1. Uniformité : Le Composite Pattern permet de traiter les objets simples et composites de manière uniforme, sans se soucier de leur complexité.
  2. Récursivité : Ce pattern est idéal pour manipuler des structures hiérarchiques comme des arbres de fichiers, des catégories, ou des systèmes de menus.
  3. Flexibilité : Il est facile d'ajouter de nouveaux types de composants ou d'étendre les composants existants sans modifier la structure de base.

Inconvénients du Composite Pattern

  1. Complexité accrue : Le Composite Pattern peut rendre le système plus complexe, surtout si la structure hiérarchique est simple et qu'il n'y a pas besoin de gérer des groupes d'objets.
  2. Difficulté à restreindre certaines actions : Parfois, il peut être difficile de restreindre certaines opérations sur des composites ou des feuilles. Par exemple, un fichier ne devrait pas pouvoir contenir d'autres composants, mais le système ne l'interdit pas par défaut.

Conclusion

Le Composite Pattern est particulièrement utile lorsque tu dois manipuler des structures hiérarchiques complexes dans ton application Laravel. Il permet de traiter des collections d'objets de manière unifiée, qu'ils soient simples ou composites. Ce pattern est idéal pour des scénarios comme la gestion des systèmes de fichiers, les catégories imbriquées, ou les structures arborescentes. Il offre une grande flexibilité tout en maintenant une séparation claire entre les composants individuels et les composites.