Composite-Muster
Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy. Lektion 99 von 110.
Das Composite-Muster ermöglicht es dir, einzelne Objekte und Gruppen von Objekten einheitlich zu behandeln. Es setzt Objekte zu Baumstrukturen zusammen, in denen sowohl einzelne Elemente als auch Sammlungen von Elementen dieselbe Schnittstelle verwenden. Das eignet sich hervorragend zur Darstellung von Hierarchien wie Dateisystemen, Organigrammen oder UI-Komponenten.
Das Muster hat zwei Arten von Beteiligten: Blatt-Knoten (einzelne Objekte ohne untergeordnete Elemente) und Kompositum-Knoten (Container, die andere Komponenten enthalten). Beide implementieren eine gemeinsame Komponente-Schnittstelle:
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');
}Die Klasse Folder kann sowohl File-Objekte als auch andere Folder-Objekte enthalten. Wenn Sie getSize() für einen Ordner aufrufen, berechnet sie rekursiv die Gesamtgröße seines gesamten Inhalts. Der Client-Code muss nicht wissen, ob er mit einer einzelnen Datei oder einer gesamten Ordnerhierarchie arbeitet – beide reagieren auf dieselben Methoden.
Aufgabe
EinfachErstellen wir ein Organisationsdiagrammsystem mit dem Composite-Muster! Du erstellst eine Struktur, in der sowohl einzelne Mitarbeiter als auch Abteilungen (die Mitarbeiter und weitere Abteilungen enthalten) einheitlich behandelt werden können – perfekt zur Darstellung von Unternehmenshierarchien.
Du organisierst deinen Code in zwei Dateien:
organization.dart: Diese Datei enthält deine Komponentenschnittstelle sowie die Blatt- und Verbundklassen. Erstelle eine abstrakte KlasseOrganizationUnitmit einemname-Getter, einergetSalaryBudget()-Methode, die einintzurückgibt, und einerdisplay([String indent = ''])-Methode zur Darstellung der Hierarchie. Erstelle eineEmployee-Klasse (das Blatt), dieOrganizationUnitimplementiert. Sie sollte einen Namen und ein Gehalt besitzen, wobeigetSalaryBudget()das Gehalt des Mitarbeiters zurückgibt. Ihredisplay()-Methode sollte[indent]- [name] ($[salary])ausgeben. Erstelle anschließend eineDepartment-Klasse (den Verbund), die ebenfallsOrganizationUnitimplementiert. Sie sollte einen Namen besitzen und eine Liste vonOrganizationUnit-Kindern verwalten. Füge eineadd()-Methode hinzu, um Mitarbeiter oder Unterabteilungen aufzunehmen. IhregetSalaryBudget()-Methode sollte rekursiv die Budgets aller Kinder summieren. Ihredisplay()-Methode sollte[indent]+ [name]/ausgeben und anschließend jedes Kind mit einer größeren Einrückung darstellen (zwei Leerzeichen hinzufügen).main.dart: Importiere deine Organisationsdatei und erstelle eine Unternehmensstruktur. Erstelle eineEngineering-Abteilung mit zwei Mitarbeitern:Alicemit einem Gehalt von80000undBobmit einem Gehalt von75000. Erstelle eineQA-Abteilung mit einem Mitarbeiter:Carolmit einem Gehalt von65000. Erstelle nun eineTechnology-Abteilung und füge sowohlEngineeringals auchQAals Unterabteilungen hinzu. Rufedisplay()für die Technology-Abteilung auf und gib anschließendTotal Budget: $gefolgt vom Gesamtgehaltsbudget aus.
Das Schöne am Composite-Muster ist, dass Technology.getSalaryBudget() automatisch die Gesamtsumme über alle verschachtelten Abteilungen und Mitarbeiter berechnet – der Client-Code muss die interne Struktur nicht kennen!
Erwartete Ausgabe:
+ Technology/
+ Engineering/
- Alice ($80000)
- Bob ($75000)
+ QA/
- Carol ($65000)
Total Budget: $220000Probier es selbst
import 'organization.dart';
void main() {
// TODO: Erstelle eine Engineering-Abteilung
// TODO: Füge Alice mit einem Gehalt von 80000 hinzu
// TODO: Füge Bob mit einem Gehalt von 75000 hinzu
// TODO: Erstelle eine QA-Abteilung
// TODO: Füge Carol mit einem Gehalt von 65000 hinzu
// TODO: Erstelle eine Technology-Abteilung
// TODO: Füge Engineering und QA als Unterabteilungen hinzu
// TODO: Rufe display() für die Technology-Abteilung auf
// TODO: Drucke "Total Budget: $" gefolgt vom gesamten Gehaltsbudget
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienBibliotheken & ImportsEinführung in die OOPKlassen vs. ObjekteDas Schlüsselwort thisMethodenInstanzvariablenGrundlagen von KonstruktorenRückblick – Einfacher Taschenrechner4Null-Sicherheit
Einführung in die Null-SicherheitNullable vs. Non-NullableDie Operatoren ? und !Late-Schlüsselwort und Null-SicherheitNull-bewusste OperatorenNull-Sicherheit in KlassenRückblick – Benutzers профilsystem7Abstrakte Klassen & Interfaces
Abstrakte KlassenAbstrakte MethodenInterfaces in DartImplizite InterfacesImplementieren vs. ErweiternMehrere InterfacesZusammenfassung – Formrechner10Collections & Generics
Übersicht über List, Set und MapTypsichere CollectionsGenerische KlassenGenerische MethodenGenerische EinschränkungenIterable & IteratorRückblick – Generischer Speicher13Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungErweiterungsmethodenAufrufbare KlassenVersiegelte Klassen (Dart 3)Records (Dart 3)Muster & Matching (3.0)Enums mit Methoden16Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen2Konstruktoren in Dart
StandardkonstruktorBenannte KonstruktorenInitialisierungslistenKonstantenkonstruktorenFactory-KonstruktorenWeiterleitende KonstruktorenRückblick – Shape Builder5Kapselung
Öffentliche vs. private MemberDie _-Präfix-KonventionBibliotheksweite SichtbarkeitTiefergehende Getter & SetterInformationsverbergungRückblick – Studierendendaten8Mixins
Einführung in MixinsMixins erstellenMehrere Mixins verwendenDas Schlüsselwort „on“ in MixinsMixin vs. VererbungMixin vs. SchnittstelleRückblick – Tiersystem11Spezielle Methoden
toString()-ÜberschreibunghashCode- & ==-ÜberschreibungComparable-Schnittstellecall()-MethodenoSuchMethod-ÜberschreibungWiederholung – Benutzerdefinierte Collection14Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFabrikmusterBeobachtermusterStrategiemuster17Abschließende Herausforderungen
E-Learning-PlattformBankingsystemSpielcharaktersystemFahrzeugvermietung3Klassen-Eigenschaften
Instanz- vs. statische MemberFinal- und Const-FelderLate-VariablenStatische Methoden und FelderGetter und SetterRückblick – Bankkontoverwaltung6Vererbung
Grundlegende VererbungDas Schlüsselwort superMethodenüberschreibungDie Annotation @overrideDas Schlüsselwort final für KlassenKonstruktoren und VererbungZusammenfassung – Mitarbeiterhierarchie9Polymorphismus
Grundlagen des PolymorphismusPolymorphismus über InterfacesLaufzeit-TypüberprüfungDie Operatoren is & asCovariant-SchlüsselwortZusammenfassung – Zahlungsprozessor12Asynchrone OOP
Futures & async/awaitStream-GrundlagenStream-ControllerAsynchrone KonstruktorenAsync in KlassenmethodenZusammenfassung – Datenabruf15Entwurfsmuster Teil 2
Command-MusterAdapter-MusterDecorator-MusterTemplate-Method-MusterState-MusterComposite-MusterRepository-MusterÜbe selbstständig: Online-Dart-Compiler