Patron Composite
Fait partie de la section Programmation Orientée Objet du Journey Java de Coddy. Leçon 75 sur 87.
Le patron Composite est un patron de conception structurel qui vous permet de composer des objets en structures arborescentes afin de représenter des hiérarchies partie-tout. Il permet aux clients de traiter uniformément les objets individuels et les compositions d’objets grâce à une interface commune.
Imagine un système de fichiers : un dossier peut contenir des fichiers et d’autres dossiers, qui peuvent eux-mêmes contenir davantage de fichiers et de dossiers. Que vous travailliez avec un seul fichier ou avec toute une structure de dossiers, vous voulez effectuer des opérations comme « obtenir la taille » de la même manière. Le modèle définit une interface Component, des objets Leaf (éléments individuels) et des objets Composite (conteneurs qui contiennent des enfants) :
interface FileComponent {
void display(String indent);
int getSize();
}
class File implements FileComponent {
private String name;
private int size;
public File(String name, int size) {
this.name = name;
this.size = size;
}
public void display(String indent) {
System.out.println(indent + name + " (" + size + "KB)");
}
public int getSize() {
return size;
}
}
class Folder implements FileComponent {
private String name;
private List<FileComponent> children = new ArrayList<>();
public Folder(String name) {
this.name = name;
}
public void add(FileComponent component) {
children.add(component);
}
public void display(String indent) {
System.out.println(indent + name + "/");
for (FileComponent child : children) {
child.display(indent + " ");
}
}
public int getSize() {
return children.stream().mapToInt(FileComponent::getSize).sum();
}
}Le composite délègue les opérations à ses enfants, ce qui permet de créer des structures récursives. Les clients interagissent avec l’arbre sans savoir s’ils travaillent avec une feuille ou un composite :
Folder root = new Folder("Documents");
root.add(new File("resume.pdf", 150));
Folder photos = new Folder("Photos");
photos.add(new File("vacation.jpg", 2000));
root.add(photos);
root.display("");
System.out.println("Total: " + root.getSize() + "KB");Le pattern Composite est idéal pour représenter des hiérarchies comme les organigrammes, les composants d’interface utilisateur ou les systèmes de menus, lorsque vous devez traiter les groupes et les éléments individuels de manière identique.
Défi
FacileConstruisons un système d'organigramme en utilisant le pattern Composite ! Vous allez créer une structure dans laquelle les services peuvent contenir des employés et d'autres sous-services, ce qui vous permettra de calculer les salaires totaux et d'afficher la hiérarchie de manière uniforme, que vous consultiez un seul employé ou une division entière.
Vous organiserez votre code sur quatre fichiers :
OrganizationComponent.java: définissez l'interface du composant que les employés et les services implémenteront. Elle doit déclarer deux méthodes :showDetails(String indent)pour afficher le composant avec l'indentation appropriée, etgetSalary(), qui renvoie le salaire total sous forme d'entier.Employee.java: créez la classe feuille représentant les employés individuels. UnEmployeepossède un nom (String) et un salaire (int), tous deux définis via le constructeur. LorsqueshowDetailsest appelée, elle doit afficher[indent][name]: $[salary]. La méthodegetSalaryrenvoie simplement le salaire de l'employé.Department.java: créez la classe composite pouvant contenir à la fois des employés et des sous-services. UnDepartmentpossède un nom (String) et conserve une liste d'enfantsOrganizationComponent. Il doit disposer d'une méthodeadd(OrganizationComponent component)pour ajouter des membres. LorsqueshowDetailsest appelée, elle affiche[indent][name] Department, puis appelleshowDetailssur chaque enfant avec une indentation accrue (ajoutez deux espaces). La méthodegetSalaryrenvoie la somme des salaires de tous les enfants.Main.java: construisez votre organisation ! Vous recevrez quatre entrées : deux noms d'employés avec leurs salaires, ainsi qu'un nom de sous-service avec un employé.Créez un service « Engineering » comme racine. Ajoutez-y deux employés en utilisant les deux premières paires nom/salaire. Créez ensuite un sous-service à partir de la troisième entrée, ajoutez-y un employé en utilisant la quatrième paire nom/salaire, puis ajoutez ce sous-service à Engineering.
Appelez
showDetails("")sur le service Engineering, puis affichez le salaire total au formatTotal Salary: $[amount].
Vous recevrez les entrées dans cet ordre : nom de employee1 (String), salaire de employee1 (int), nom de employee2 (String), salaire de employee2 (int), nom du sous-service (String), nom de employee3 (String), salaire de employee3 (int).
Par exemple, avec les entrées Alice, 75000, Bob, 65000, QA, Charlie, 55000, votre résultat serait :
Engineering Department
Alice: $75000
Bob: $65000
QA Department
Charlie: $55000
Total Salary: $195000Remarquez comment les mêmes méthodes showDetails et getSalary fonctionnent parfaitement, qu'elles soient appelées sur un seul employé ou sur un service entier contenant des sous-services imbriqués. La structure composite gère automatiquement la récursion, ce qui vous permet de traiter toute la hiérarchie de manière uniforme !
Essayez vous-même
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Lire les entrées
String emp1Name = scanner.nextLine();
int emp1Salary = Integer.parseInt(scanner.nextLine());
String emp2Name = scanner.nextLine();
int emp2Salary = Integer.parseInt(scanner.nextLine());
String subDeptName = scanner.nextLine();
String emp3Name = scanner.nextLine();
int emp3Salary = Integer.parseInt(scanner.nextLine());
// TODO: Create the "Engineering" department as the root
// TODO: Créer et ajouter deux employés à Engineering en utilisant les données emp1 et emp2
// TODO: Créer un sous-département en utilisant subDeptName
// TODO: Créer et ajouter un employé au sous-département en utilisant les données emp3
// TODO: Ajouter le sous-département à Engineering
// TODO: Call showDetails("") on the Engineering department
// 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 vs ObjetsLe mot-clé thisMéthodesChamps (Attributs)Méthode constructeurSurcharge de constructeurRécapitulatif - Calculatrice simple4Héritage
Héritage de base (extends)Le mot-clé superRedéfinition de méthode (@Override)Chaînage de constructeursLa classe ObjectHéritage simple et multiniveauPourquoi pas d'héritage multiple de classesRécapitulatif - Hiérarchie des employés7Méthodes spéciales et classe Object
Méthode toString()equals() et hashCode()Méthode clone()compareTo() et ComparableInterface ComparatorRécapitulatif - Tri personnalisé2Modificateurs d'accès et Encapsulation
Aperçu des niveaux d'accèsMéthodes Getter et SetterMasquage d'informationsLe mot-clé finalRécapitulatif - Gestionnaire de compte bancaire5Polymorphisme
Bases de la surcharge de méthodesRedéfinition de méthodes (Run-Time)Upcasting et DowncastingL'opérateur instanceofClasses et méthodes abstraitesRécapitulatif - Calculateur de formes8Concepts avancés de la POO
Composition vs HéritageAgrégation vs CompositionClasses internes, imbriquées et anonymesEnums et méthodes d'EnumRecords (Java 16+)Classes scellées (Java 17+)11Patrons de conception, partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FabriquePatron MonteurPatron ObservateurPatron Stratégie3Propriétés de classe et membres statiques
Variables d'instance vs variables statiquesMéthodes statiquesBlocs statiquesConstantes (static final)Récapitulatif - Compteur et utilitaire6Interfaces et Classes Abstraites
Introduction aux InterfacesImplémentation d'InterfacesImplémentation d'Interfaces MultiplesDefault et Static dans les InterfacesClasses Abstraites vs InterfacesInterfaces FonctionnellesRécapitulatif - Système de Paiement9La généricité
Introduction à la généricitéClasses génériquesMéthodes génériquesParamètres de type bornésWildcards (?, extends, super)Récapitulatif - Conteneur générique12Patrons de conception, partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositePatron ItérateurEntraînez-vous par vous-même : Compilateur Java en ligne