Menu
Coddy logo textTech

Patron Composite

Fait partie de la section Programmation Orientée Objet du Journey PHP de Coddy. Leçon 80 sur 91.

Le pattern Composite est un patron de conception structurel qui vous permet de composer des objets en structures arborescentes, puis de travailler avec ces structures comme s’il s’agissait d’objets individuels. Il est parfait pour représenter des hiérarchies partie-tout dans lesquelles vous souhaitez traiter uniformément les objets uniques et les groupes d’objets.

Considérez un système de fichiers. Un dossier peut contenir des fichiers et d’autres dossiers.

Lorsque vous calculez la taille totale, vous souhaitez appeler la même méthode sur les fichiers et les dossiers, et les dossiers doivent additionner récursivement leur contenu. Le pattern Composite rend cela transparent en donnant la même interface aux feuilles (fichiers) et aux composites (dossiers).

<?php
interface FileSystemItem {
    public function getName(): string;
    public function getSize(): int;
}

class File implements FileSystemItem {
    public function __construct(
        private string $name,
        private int $size
    ) {}
    
    public function getName(): string {
        return $this->name;
    }
    
    public function getSize(): int {
        return $this->size;
    }
}

class Folder implements FileSystemItem {
    private array $items = [];
    
    public function __construct(private string $name) {}
    
    public function getName(): string {
        return $this->name;
    }
    
    public function add(FileSystemItem $item): void {
        $this->items[] = $item;
    }
    
    public function getSize(): int {
        $total = 0;
        foreach ($this->items as $item) {
            $total += $item->getSize();
        }
        return $total;
    }
}

Vous pouvez maintenant créer des structures arborescentes et les traiter uniformément :

<?php
$docs = new Folder("Documents");
$docs->add(new File("resume.pdf", 250));
$docs->add(new File("cover.docx", 50));

$images = new Folder("Images");
$images->add(new File("photo.jpg", 1500));

$root = new Folder("Root");
$root->add($docs);
$root->add($images);
$root->add(new File("readme.txt", 10));

echo $root->getSize();

Sortie :

1810

Le code client appelle getSize() sans se soucier de savoir s’il traite un seul file ou une structure de folder profondément imbriquée. Le motif gère la récursivité en interne, ce qui facilite l’utilisation de hiérarchies complexes.

challenge icon

Défi

Facile

Construisons un système d'organigramme en utilisant le modèle Composite. Les entreprises ont une structure hiérarchique où les services peuvent contenir des employés et d'autres sous-services : une structure arborescente parfaite lorsque vous souhaitez calculer les totaux uniformément dans toute l'organisation.

Vous organiserez votre code dans quatre fichiers :

  • OrganizationUnit.php : définissez une interface OrganizationUnit que les employés individuels et les services implémenteront. Elle doit comporter deux méthodes : getName(): string et getSalary(): int. Cette interface commune vous permet de traiter les employés individuels et les services entiers de la même manière lors du calcul des coûts.
  • Employee.php : incluez l'interface OrganizationUnit et créez une classe Employee qui l'implémente. Un employé est un nœud feuille dans votre arbre organisationnel. Il possède un nom et un salaire, mais ne peut pas contenir d'autres unités. Utilisez la promotion de constructeur pour accepter le nom et le salaire, puis implémentez les deux méthodes de l'interface.
  • Department.php : incluez l'interface OrganizationUnit et créez une classe Department qui l'implémente. Un service est un composite qui peut contenir à la fois des employés et d'autres services. Votre service doit :
    • Accepter un nom dans son constructeur
    • Implémenter getName() pour renvoyer le nom du service
    • Disposer d'une méthode add(OrganizationUnit $unit): void pour ajouter des employés ou des sous-services
    • Implémenter getSalary() pour renvoyer le salaire total de toutes les unités qu'il contient (en additionnant récursivement tout ce qui se trouve à l'intérieur)
  • main.php : incluez les fichiers Employee et Department. Vous recevrez une entrée : une chaîne JSON représentant la structure de l'organisation.

    Le JSON sera au format suivant :

    {"Engineering": [{"name": "Alice", "salary": 80000}, {"name": "Bob", "salary": 75000}], "Sales": [{"name": "Carol", "salary": 65000}]}

    Chaque clé est un nom de service, et sa valeur est un tableau d'employés avec leurs noms et leurs salaires.

    Créez un Department racine appelé "Company". Pour chaque service du JSON, créez un Department, ajoutez-y ses employés, puis ajoutez ce service à Company. Enfin, affichez le salaire total de l'entreprise dans ce format :

    Total Salary: [amount]

La beauté du modèle Composite réside dans le fait que l'appel de getSalary() sur le service Company calcule automatiquement la somme de tous les services et employés imbriqués : le code client n'a pas besoin de connaître la structure interne.

Essayez vous-même

<?php
require_once 'Employee.php';
require_once 'Department.php';

// Lire l'entrée JSON
$input = trim(fgets(STDIN));
$data = (array)json_decode($input, true);

// TODO: Créer un Department racine appelé "Company"

// TODO: Parcourir chaque department dans les données JSON
// Pour chaque department :
//   - Créer un nouvel objet Department
//   - Ajouter chaque employee à ce department
//   - Ajouter le department à la Company

// TODO: Afficher le salaire total au format : Total Salary: [amount]

?>
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet

Entraînez-vous par vous-même : Compilateur PHP en ligne