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 :
1810Le 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.
Défi
FacileConstruisons 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 interfaceOrganizationUnitque les employés individuels et les services implémenteront. Elle doit comporter deux méthodes :getName(): stringetgetSalary(): 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 classeEmployeequi 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 classeDepartmentqui 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): voidpour 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
Departmentracine appelé"Company". Pour chaque service du JSON, créez unDepartment, 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]
?>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
1Fondamentaux de la POO
Fichiers externesIntroduction à la POOClasses et objetsLe mot-clé $thisMéthodesPropriétésConstructeur (__construct)Destructeur (__destruct)Récapitulatif - Calculatrice simple4Héritage
Héritage de baseLe mot-clé parent::Redéfinition des méthodesLe mot-clé finalClasses abstraitesRécapitulatif – Hiérarchie des employés7Encapsulation
Public, Protected, PrivateModificateurs d’accès en profondeurAccesseurs et mutateursDissimulation de l’informationPromotion des constructeurs (8.0)Récapitulatif – Système de fiches étudiant10Concepts avancés de la POO
Composition ou héritageInjection de dépendancesClasses anonymesÉnumérations (PHP 8.1)Fibres (PHP 8.1)Approfondissement du clonage d’objetsGénérateurs et itérateurs13Patrons de conception – Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode modèlePatron ÉtatPatron CompositePatron Dépôt2Espaces de noms et chargement automatique
Introduction aux espaces de nomsLe mot-clé useNorme de chargement automatique PSR-4Autoloader de ComposerRécapitulatif - Projet organisé5Interfaces et contrats
Introduction aux interfacesImplémentation des interfacesImplémentation de plusieurs interfacesInterface ou classe abstraiteIndication de type avec les interfacesRécapitulatif - Calculateur de formes8Méthodes magiques
Introduction aux méthodes magiques__toString et __debugInfo__get, __set, __isset, __unset__call et __callStatic__clone et clonage d’objets__serialize et __unserializeRécapitulatif - Collection personnalisée3Propriétés de classe
Propriétés d’instance vs statiquesConstantes dans les classesMéthodes et propriétés statiquesPropriétés privées et protégéesPropriétés en lecture seule (PHP 8.1)Récapitulatif - Gestionnaire de comptes bancaires6Polymorphisme
Révision de la redéfinition des méthodesPolymorphisme via les interfacesAnnotations de type et types unionLiaison statique tardiveRécapitulatif - Processeur de paiements9Traits
Introduction aux traitsUtilisation de plusieurs traitsRésolution des conflits entre traitsMéthodes abstraites dans les traitsTraits par rapport à l’héritage12Patrons de conception – Partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FactoryPatron ObserverPatron StrategyEntraînez-vous par vous-même : Compilateur PHP en ligne