Menu
Coddy logo textTech

Pattern Composite

Fa parte della sezione Programmazione orientata agli oggetti del percorso Java di Coddy. Lezione 75 di 87.

Il Composite Pattern è un pattern strutturale che consente di comporre oggetti in strutture ad albero per rappresentare gerarchie parte-tutto. Permette ai client di trattare in modo uniforme oggetti singoli e composizioni di oggetti tramite un'interfaccia comune.

Pensa a un file system: una cartella può contenere file e altre cartelle, che a loro volta possono contenere altri file e cartelle. Che tu abbia a che fare con un singolo file o con un’intera struttura di cartelle, vuoi eseguire operazioni come «ottenere le dimensioni» sempre allo stesso modo. Il pattern definisce un’interfaccia Component, oggetti Leaf (elementi singoli) e oggetti Composite (contenitori che ospitano elementi figli):

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();
    }
}

Il composito delega le operazioni ai suoi figli, consentendo strutture ricorsive. I client interagiscono con l'albero senza sapere se stanno lavorando con una foglia o con un composito:

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");

Il pattern Composite è ideale per rappresentare gerarchie come organigrammi, componenti dell’interfaccia utente o sistemi di menu, in cui devi trattare gruppi e singoli elementi in modo identico.

challenge icon

Sfida

Facile

Costruiamo un sistema di organigrammi usando il Composite Pattern! Creerai una struttura in cui i reparti possono contenere dipendenti e altri sottoreparti, permettendoti di calcolare gli stipendi totali e visualizzare la gerarchia in modo uniforme, sia che tu stia esaminando un singolo dipendente sia un'intera divisione.

Organizzerai il codice in quattro file:

  • OrganizationComponent.java: Definisci l'interfaccia del componente che sarà implementata sia dai dipendenti sia dai reparti. Dovrebbe dichiarare due metodi: showDetails(String indent) per visualizzare il componente con la corretta indentazione e getSalary(), che restituisce lo stipendio totale come numero intero.
  • Employee.java: Crea la classe foglia che rappresenta i singoli lavoratori. Un Employee ha un nome (String) e uno stipendio (int), entrambi impostati tramite il costruttore. Quando viene chiamato showDetails, dovrebbe stampare [indent][name]: $[salary]. Il metodo getSalary restituisce semplicemente lo stipendio del dipendente.
  • Department.java: Crea la classe composita che può contenere sia dipendenti sia sottoreparti. Un Department ha un nome (String) e mantiene un elenco di elementi figli OrganizationComponent. Dovrebbe avere un metodo add(OrganizationComponent component) per aggiungere membri. Quando viene chiamato showDetails, stampa [indent][name] Department, quindi chiama showDetails su ogni elemento figlio con un'indentazione maggiore (aggiungi due spazi). Il metodo getSalary restituisce la somma degli stipendi di tutti gli elementi figli.
  • Main.java: Crea la tua organizzazione! Riceverai quattro input: i nomi e gli stipendi di due dipendenti e il nome di un sottoreparto con un dipendente.

    Crea un reparto "Engineering" come radice. Aggiungici due dipendenti usando le prime due coppie nome/stipendio. Poi crea un sottoreparto usando il terzo input, aggiungici un dipendente usando la quarta coppia nome/stipendio e aggiungi questo sottoreparto a Engineering.

    Chiama showDetails("") sul reparto Engineering, quindi stampa lo stipendio totale nel formato Total Salary: $[amount].

Riceverai gli input in questo ordine: nome di employee1 (String), stipendio di employee1 (int), nome di employee2 (String), stipendio di employee2 (int), nome del sottoreparto (String), nome di employee3 (String), stipendio di employee3 (int).

Ad esempio, con gli input Alice, 75000, Bob, 65000, QA, Charlie, 55000, il tuo output sarebbe:

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

Nota come gli stessi metodi showDetails e getSalary funzionano senza problemi sia quando vengono chiamati su un singolo dipendente sia su un intero reparto contenente sottoreparti annidati. La struttura composita gestisce automaticamente la ricorsione, permettendoti di trattare uniformemente l'intera gerarchia!

Provalo tu

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Read inputs
        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: Create and add two employees to Engineering using emp1 and emp2 data
        
        // TODO: Create a sub-department using subDeptName
        
        // TODO: Create and add one employee to the sub-department using emp3 data
        
        // TODO: Add the sub-department to Engineering
        
        // TODO: Call showDetails("") on the Engineering department
        
        // TODO: Print the total salary in format: Total Salary: $[amount]
    }
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Java online