Menu
Coddy logo textTech

Pattern Composite

Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 99 di 110.

Il pattern Composite ti permette di trattare in modo uniforme i singoli oggetti e i gruppi di oggetti. Compone gli oggetti in strutture ad albero in cui sia i singoli elementi sia le raccolte di elementi condividono la stessa interfaccia. È perfetto per rappresentare gerarchie come file system, organigrammi o componenti dell’interfaccia utente.

Il pattern ha due tipi di partecipanti: nodi Leaf (oggetti individuali senza figli) e nodi Composite (contenitori che ospitano altri componenti). Entrambi implementano un'interfaccia Component comune:

abstract class FileSystemItem {
  String get name;
  int getSize();
  void display([String indent = '']);
}

class File implements FileSystemItem {
  @override
  final String name;
  final int size;

  File(this.name, this.size);

  @override
  int getSize() => size;

  @override
  void display([String indent = '']) {
    print('$indent- $name ($size KB)');
  }
}

class Folder implements FileSystemItem {
  @override
  final String name;
  final List<FileSystemItem> _children = [];

  Folder(this.name);

  void add(FileSystemItem item) => _children.add(item);

  @override
  int getSize() => _children.fold(0, (sum, item) => sum + item.getSize());

  @override
  void display([String indent = '']) {
    print('$indent+ $name/');
    for (var child in _children) {
      child.display('$indent  ');
    }
  }
}

void main() {
  var docs = Folder('Documents');
  docs.add(File('resume.pdf', 150));
  docs.add(File('photo.jpg', 2400));

  var projects = Folder('Projects');
  projects.add(File('main.dart', 25));
  docs.add(projects);

  docs.display();
  print('Total: ${docs.getSize()} KB');
}

La classe Folder può contenere sia oggetti File sia altri oggetti Folder. Quando chiami getSize() su una cartella, calcola ricorsivamente la dimensione totale di tutti i suoi contenuti. Il codice client non deve sapere se sta lavorando con un singolo file o con un'intera gerarchia di cartelle: entrambi rispondono agli stessi metodi.

challenge icon

Sfida

Facile

Creiamo un sistema di organigrammi usando il pattern Composite! Creerai una struttura in cui sia i singoli dipendenti sia i reparti (che contengono dipendenti e altri reparti) possono essere trattati in modo uniforme: perfetta per rappresentare le gerarchie aziendali.

Organizzerai il codice in due file:

  • organization.dart: questo file contiene l’interfaccia del componente e sia le classi foglia sia quelle composite. Crea una classe astratta OrganizationUnit con un getter name, un metodo getSalaryBudget() che restituisce un int e un metodo display([String indent = '']) per mostrare la gerarchia. Crea una classe Employee (la foglia) che implementa OrganizationUnit. Dovrebbe avere un nome e uno stipendio, e getSalaryBudget() dovrebbe restituire lo stipendio del dipendente. Il suo display() dovrebbe stampare [indent]- [name] ($[salary]). Poi crea una classe Department (il composito) che implementa anch’essa OrganizationUnit. Dovrebbe avere un nome e mantenere un elenco di elementi figli di tipo OrganizationUnit. Aggiungi un metodo add() per includere dipendenti o sottoreparti. Il suo getSalaryBudget() dovrebbe calcolare ricorsivamente la somma dei budget di tutti gli elementi figli. Il suo display() dovrebbe stampare [indent]+ [name]/, seguito dalla visualizzazione di ogni elemento figlio con un’indentazione maggiore (aggiungi due spazi).
  • main.dart: importa il file dell’organizzazione e crea la struttura aziendale. Crea un reparto Engineering contenente due dipendenti: Alice con uno stipendio di 80000 e Bob con uno stipendio di 75000. Crea un reparto QA con un dipendente: Carol con uno stipendio di 65000. Ora crea un reparto Technology e aggiungi sia Engineering sia QA come sottoreparti. Chiama display() sul reparto Technology, poi stampa Total Budget: $ seguito dal budget totale degli stipendi.

Il bello del pattern Composite è che Technology.getSalaryBudget() calcola automaticamente il totale di tutti i reparti e i dipendenti annidati: il codice client non deve conoscere la struttura interna!

Output previsto:

+ Technology/
  + Engineering/
    - Alice ($80000)
    - Bob ($75000)
  + QA/
    - Carol ($65000)
Total Budget: $220000

Provalo tu

import 'organization.dart';

void main() {
  // TODO: Crea un dipartimento Engineering
  // TODO: Aggiungi Alice con uno stipendio di 80000
  // TODO: Aggiungi Bob con uno stipendio di 75000
  
  // TODO: Crea un dipartimento QA
  // TODO: Aggiungi Carol con uno stipendio di 65000
  
  // TODO: Crea un dipartimento Technology
  // TODO: Aggiungi Engineering e QA come sottodipartimenti
  
  // TODO: Chiama display() sul dipartimento Technology
  
  // TODO: Stampa "Total Budget: $" seguito dal budget totale per gli stipendi
}
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 Dart online