Menu
CoddyTech

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.

Pense à un système de fichiers : un dossier peut contenir des fichiers et d’autres dossiers, qui peuvent contenir encore plus de fichiers et de dossiers. Que tu manipules un seul fichier ou toute une structure de dossiers, tu veux effectuer des opérations comme « obtenir la taille » de la même manière. Ce modèle définit une interface Component, des objets Leaf (éléments individuels) et des objets Composite (conteneurs qui contiennent des éléments 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 patron Composite est idéal pour représenter des hiérarchies comme des organigrammes, des composants d’interface utilisateur ou des systèmes de menus, lorsque tu dois traiter les groupes et les individus de manière identique.

challenge icon

Défi

Facile

Construisons un système d’organigramme à l’aide du patron Composite ! Tu vas créer une structure dans laquelle les départements peuvent contenir des employés et d’autres sous-départements, ce qui te permettra de calculer les salaires totaux et d’afficher la hiérarchie de manière uniforme, que tu consultes un seul employé ou une division entière.

Tu vas répartir ton code dans quatre fichiers :

  • OrganizationComponent.java : définis l’interface du composant que les employés et les départements implémenteront. Elle doit déclarer deux méthodes : showDetails(String indent) pour afficher le composant avec une indentation appropriée, et getSalary() qui renvoie le salaire total sous forme d’entier.
  • Employee.java : crée la classe feuille représentant les employés individuels. Un Employee possède un nom (String) et un salaire (int), tous deux définis par le constructeur. Lorsque showDetails est appelée, elle doit afficher [indent][name]: $[salary]. La méthode getSalary renvoie simplement le salaire de l’employé.
  • Department.java : crée la classe composite qui peut contenir à la fois des employés et des sous-départements. Un Department possède un nom (String) et conserve une liste d’enfants OrganizationComponent. Il doit avoir une méthode add(OrganizationComponent component) pour ajouter des membres. Lorsque showDetails est appelée, elle affiche [indent][name] Department, puis appelle showDetails sur chaque enfant avec une indentation accrue (ajoute deux espaces). La méthode getSalary renvoie la somme des salaires de tous les enfants.
  • Main.java : construis ton organisation ! Tu recevras quatre entrées : les noms et salaires de deux employés, puis le nom d’un sous-département et les informations d’un employé.

    Crée un département "Engineering" comme racine. Ajoute-y deux employés à l’aide des deux premières paires nom/salaire. Crée ensuite un sous-département à l’aide de la troisième entrée, ajoute-y un employé à l’aide de la quatrième paire nom/salaire, puis ajoute ce sous-département à Engineering.

    Appelle showDetails("") sur le département Engineering, puis affiche le salaire total au format Total Salary: $[amount].

Tu recevras 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-département (String), nom de employee3 (String), salaire de employee3 (int).

Par exemple, avec les entrées Alice, 75000, Bob, 65000, QA, Charlie, 55000, ta sortie serait :

Engineering Department
  Alice: $75000
  Bob: $65000
  QA Department
    Charlie: $55000
Total Salary: $195000

Remarque que les mêmes méthodes showDetails et getSalary fonctionnent parfaitement, qu’elles soient appelées sur un seul employé ou sur un département entier contenant des sous-départements imbriqués. La structure composite gère automatiquement la récursivité, ce qui te 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 données d’entrée
        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: Créer le département "Engineering" comme racine
        
        // TODO: Créer et ajouter deux employés à Engineering à partir des données de emp1 et emp2
        
        // TODO: Créer un sous-département à partir de subDeptName
        
        // TODO: Créer et ajouter un employé au sous-département à partir des données de emp3
        
        // TODO: Ajouter le sous-département à Engineering
        
        // TODO: Appeler showDetails("") sur le département Engineering
        
        // 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 Java en ligne