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.
Sfida
FacileCreiamo 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 astrattaOrganizationUnitcon un gettername, un metodogetSalaryBudget()che restituisce uninte un metododisplay([String indent = ''])per mostrare la gerarchia. Crea una classeEmployee(la foglia) che implementaOrganizationUnit. Dovrebbe avere un nome e uno stipendio, egetSalaryBudget()dovrebbe restituire lo stipendio del dipendente. Il suodisplay()dovrebbe stampare[indent]- [name] ($[salary]). Poi crea una classeDepartment(il composito) che implementa anch’essaOrganizationUnit. Dovrebbe avere un nome e mantenere un elenco di elementi figli di tipoOrganizationUnit. Aggiungi un metodoadd()per includere dipendenti o sottoreparti. Il suogetSalaryBudget()dovrebbe calcolare ricorsivamente la somma dei budget di tutti gli elementi figli. Il suodisplay()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 repartoEngineeringcontenente due dipendenti:Alicecon uno stipendio di80000eBobcon uno stipendio di75000. Crea un repartoQAcon un dipendente:Carolcon uno stipendio di65000. Ora crea un repartoTechnologye aggiungi siaEngineeringsiaQAcome sottoreparti. Chiamadisplay()sul reparto Technology, poi stampaTotal 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: $220000Provalo 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
}
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
1Fondamenti della programmazione orientata agli oggetti
File esterniLibrerie e importazioniIntroduzione alla programmazione orientata agli oggettiClassi e oggettiLa parola chiave thisMetodiVariabili di istanzaFondamenti dei costruttoriRiepilogo - Calcolatrice semplice4Sicurezza dei valori null
Introduzione alla sicurezza dei valori nullNullable e non nullableGli operatori ? e !La keyword late e la sicurezza dei valori nullOperatori null-awareSicurezza dei valori null nelle classiRiepilogo - Sistema di profili utente7Classi astratte e interfacce
Classi astratteMetodi astrattiInterfacce in DartInterfacce impliciteImplementare vs estendereInterfacce multipleRiepilogo - Calcolatore di forme10Collezioni e generici
Panoramica di List, Set e MapCollezioni sicure rispetto ai tipiClassi genericheMetodi genericiVincoli sui genericiIterable e IteratorRiepilogo - Archiviazione generica13Concetti avanzati di OOP
Composizione vs ereditarietàMetodi di estensioneClassi chiamabiliClassi sealed (Dart 3)Record (Dart 3)Pattern e matching (3.0)Enum con metodi16Progetto: Gestione della biblioteca
Panoramica del progettoClassi Libro e Utente2I costruttori in Dart
Costruttore predefinitoCostruttori con nomeListe di inizializzazioneCostruttori costantiCostruttori factoryCostruttori di reindirizzamentoRiepilogo - Crea forme5Incapsulamento
Membri pubblici e privatiConvenzione del prefisso _Visibilità a livello di libreriaApprofondimento su getter e setterNascondimento delle informazioniRiepilogo - Registri degli studenti8Mixin
Introduzione ai MixinCreare MixinUsare più MixinParola chiave on nei MixinMixin vs ereditarietàMixin vs interfacciaRiepilogo - Sistema animale11Metodi speciali
Sovrascrittura di toString()Sovrascrittura di hashCode e ==Interfaccia ComparableMetodo call()Sovrascrittura di noSuchMethodRiepilogo - Collezione personalizzata14Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneSingletonFactoryObserverStrategy3Proprietà delle classi
Membri di istanza e staticiCampi final e constVariabili lateMetodi e campi staticiGetter e setterRiepilogo - Gestore di conti bancari6Ereditarietà
Ereditarietà di baseLa parola chiave superOverride dei metodiL’annotazione @overrideLa parola chiave final per le classiCostruttori ed ereditarietàRiepilogo - Gerarchia dei dipendenti9Polimorfismo
Fondamenti di polimorfismoPolimorfismo tramite interfacceControllo del tipo a runtimeGli operatori is e asParola chiave covariantRiepilogo - Elaboratore di pagamenti12OOP asincrona
Future e async/awaitNozioni di base sugli streamController degli streamCostruttori asincroniAsync nei metodi di classeRiepilogo - Recupero dei dati15Pattern di progettazione Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositePattern RepositoryEsercitati da solo: Compilatore Dart online