Fabrikmuster
Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy. Lektion 91 von 110.
Das Factory pattern delegiert die Objekterstellung an eine separate Methode oder Klasse und ermöglicht es dir, Objekte zu erstellen, ohne ihre genaue Klasse anzugeben. Dies unterscheidet sich vom Factory-Konstruktor, den du zuvor kennengelernt hast – das Factory pattern ist ein Entwurfsansatz, bei dem die Erstellungslogik zentralisiert ist und abhängig von der Eingabe unterschiedliche Typen zurückgeben kann.
Stell dir ein Szenario vor, in dem du verschiedene Arten von Benachrichtigungen erstellen musst. Anstatt dass der Client entscheidet, welche Klasse instanziiert werden soll, übernimmt eine Factory diese Entscheidung:
abstract class Notification {
void send(String message);
}
class EmailNotification implements Notification {
@override
void send(String message) => print('Email: $message');
}
class SMSNotification implements Notification {
@override
void send(String message) => print('SMS: $message');
}
class NotificationFactory {
static Notification create(String type) {
switch (type) {
case 'email':
return EmailNotification();
case 'sms':
return SMSNotification();
default:
return EmailNotification();
}
}
}
void main() {
var notification = NotificationFactory.create('sms');
notification.send('Hello!'); // SMS: Hello!
}Der Client-Code muss nichts über EmailNotification oder SMSNotification wissen – er bittet die Factory einfach um eine Benachrichtigung eines bestimmten Typs. Dadurch lassen sich neue Benachrichtigungstypen leicht hinzufügen: Du änderst nur die Factory, nicht jede Stelle, an der Benachrichtigungen erstellt werden.
Verwende das Factory-Muster, wenn die Objekterstellung komplexe Logik umfasst, wenn du Implementierungsklassen vor Clients verbergen möchtest oder wenn der genaue zu erstellende Typ von Laufzeitbedingungen abhängt.
Aufgabe
EinfachErstellen wir einen Dokumentgenerator mit dem Factory-Muster! Du erstellst ein System, das verschiedene Dokumenttypen (Berichte, Rechnungen und Briefe) über eine zentrale Factory erzeugt, sodass der Client-Code die spezifischen Dokumentklassen nicht kennen muss.
Du organisierst deinen Code in zwei Dateien:
document_factory.dart: Erstelle hier dein Dokumentensystem:- Eine abstrakte Klasse
Documentmit einer Methodegenerate(String content), die einenStringzurückgibt - Drei konkrete Klassen, die
Documentimplementieren:Report– ihregenerate-Methode gibt=== REPORT ===\n[content]\n=============zurückInvoice– ihregenerate-Methode gibtINVOICE\n--------\n[content]\nTotal DuezurückLetter– ihregenerate-Methode gibtDear Reader,\n[content]\nSincerelyzurück
- Eine Klasse
DocumentFactorymit einer statischen Methodecreate(String type), die abhängig vom Typ-StringDocument,"report"oder"invoice"das passende"letter"zurückgibt. Für jeden unbekannten Typ soll standardmäßig einLetterzurückgegeben werden
- Eine abstrakte Klasse
main.dart: Importiere deine Dokument-Factory und zeige, wie die Factory verschiedene Dokumenttypen erstellt, ohne dass der Client die konkreten Klassen kennen muss:- Verwende die Factory, um einen Bericht zu erstellen, und gib das Ergebnis seiner Generierung mit dem Inhalt
Sales increased by 25%aus - Gib eine leere Zeile aus
- Verwende die Factory, um eine Rechnung zu erstellen, und gib das Ergebnis ihrer Generierung mit dem Inhalt
Widget x3 - $150aus - Gib eine leere Zeile aus
- Verwende die Factory, um einen Brief zu erstellen, und gib das Ergebnis seiner Generierung mit dem Inhalt
Thank you for your orderaus
- Verwende die Factory, um einen Bericht zu erstellen, und gib das Ergebnis seiner Generierung mit dem Inhalt
Beachte, dass deine Hauptdatei nur mit der Factory und dem abstrakten Typ Document interagiert – sie erstellt niemals direkt Objekte von Report, Invoice oder Letter!
Erwartete Ausgabe:
=== REPORT ===
Sales increased by 25%
=============
INVOICE
--------
Widget x3 - $150
Total Due
Dear Reader,
Thank you for your order
SincerelyProbier es selbst
import 'document_factory.dart';
void main() {
// TODO: Verwende DocumentFactory.create(), um einen Bericht zu erstellen
// Gib dann das Ergebnis der Generierung mit dem Inhalt "Sales increased by 25%" aus
// TODO: Gib eine Leerzeile aus
// TODO: Verwende DocumentFactory.create(), um eine Rechnung zu erstellen
// Gib dann das Ergebnis der Generierung mit dem Inhalt "Widget x3 - \$150" aus
// TODO: Gib eine Leerzeile aus
// TODO: Verwende DocumentFactory.create(), um einen Brief zu erstellen
// Gib dann das Ergebnis der Generierung mit dem Inhalt "Thank you for your order" aus
}
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 – ZahlungsprozessorÜbe selbstständig: Online-Dart-Compiler