Factory-Konstruktoren
Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy — Lektion 14 von 110.
Ein Factory-Konstruktor ist ein spezieller Konstruktor, der nicht immer eine neue Instanz erstellt. Im Gegensatz zu regulären Konstruktoren kann ein Factory-Konstruktor eine bestehende Instanz, einen Subtyp oder sogar null (falls nullbar) zurückgeben. Sie deklarieren ihn mit dem Schlüsselwort factory.
class Logger {
static final Logger _instance = Logger._internal();
// Privater benannter Konstruktor
Logger._internal();
// Factory-Konstruktor
factory Logger() {
return _instance;
}
}
Logger log1 = Logger();
Logger log2 = Logger();
print(identical(log1, log2)); // trueIn diesem Beispiel gibt der Factory-Konstruktor immer dieselbe Instanz zurück. Egal wie oft Sie Logger() aufrufen, Sie erhalten das identische Objekt. Dieses Muster wird häufig zur Implementierung von Singletons verwendet.
Factory-Konstruktoren unterscheiden sich von regulären Konstruktoren in einem wesentlichen Punkt: Sie haben keinen Zugriff auf this, da sie möglicherweise gar keine neue Instanz erstellen. Stattdessen müssen sie explizit ein Objekt zurückgeben:
class Shape {
factory Shape(String type) {
if (type == 'circle') return Circle();
if (type == 'square') return Square();
return Rectangle();
}
}
class Circle extends Shape { Circle() : super._(); }
class Square extends Shape { Square() : super._(); }
class Rectangle extends Shape { Rectangle() : super._(); }Factory-Konstruktoren sind nützlich, wenn Sie die Kontrolle über die Instanzerstellung benötigen, z. B. um zwischengespeicherte Objekte zurückzugeben, Objekt-Pools zu implementieren oder zu entscheiden, welcher Subtyp basierend auf den Eingabeparametern instanziiert werden soll.
Aufgabe
EinfachLassen Sie uns ein Benachrichtigungssystem erstellen, das Factory-Konstruktoren verwendet, um verschiedene Arten von Benachrichtigungen basierend auf einer einfachen String-Eingabe zu erstellen.
Sie werden zwei Dateien erstellen, um Ihren Code zu organisieren:
notification.dart: Definieren Sie eineNotification-Klasse, die als Basis für alle Benachrichtigungstypen dient. Ihre Klasse sollte Folgendes haben:- Ein
String messageFeld - Einen privaten benannten Konstruktor
Notification._internal, der die Nachricht initialisiert - Einen Factory-Konstruktor
Notification(String type, String message), der basierend auf dem Parametertypeverschiedene Benachrichtigungs-Subtypen zurückgibt:- Wenn der Typ
'email'ist, geben Sie eineEmailNotificationzurück - Wenn der Typ
'sms'ist, geben Sie eineSMSNotificationzurück - Andernfalls geben Sie eine
PushNotificationzurück
- Wenn der Typ
- Eine
send()Methode, dieSending: [message]ausgibt
- Ein
Erstellen Sie in derselben Datei drei Unterklassen, die Notification erweitern:
EmailNotification: Überschreiben Siesend(), umEmail: [message]auszugebenSMSNotification: Überschreiben Siesend(), umSMS: [message]auszugebenPushNotification: Überschreiben Siesend(), umPush: [message]auszugeben
Jede Unterklasse benötigt einen Konstruktor, der eine message entgegennimmt und diese mit super._internal(message) an die Elternklasse übergibt.
main.dart: Importieren Sie Ihre Benachrichtigungsklasse und erstellen Sie drei Benachrichtigungen mit dem Factory-Konstruktor:- Eine E-Mail-Benachrichtigung mit der Nachricht
'Welcome!' - Eine SMS-Benachrichtigung mit der Nachricht
'Your code is 1234' - Eine Push-Benachrichtigung mit der Nachricht
'New update available'
send()für jede Benachrichtigung in der oben aufgeführten Reihenfolge auf.- Eine E-Mail-Benachrichtigung mit der Nachricht
Erwartete Ausgabe:
Email: Welcome!
SMS: Your code is 1234
Push: New update availableSpickzettel
Ein Factory-Konstruktor ist ein spezieller Konstruktor, der mit dem Schlüsselwort factory deklariert wird und nicht immer eine neue Instanz erstellt. Im Gegensatz zu regulären Konstruktoren kann er eine bestehende Instanz, einen Subtyp oder null zurückgeben.
Factory-Konstruktoren haben keinen Zugriff auf this und müssen explizit ein Objekt zurückgeben.
Beispiel für das Singleton-Muster:
class Logger {
static final Logger _instance = Logger._internal();
Logger._internal(); // Privater benannter Konstruktor
factory Logger() {
return _instance; // Gibt immer dieselbe Instanz zurück
}
}
Logger log1 = Logger();
Logger log2 = Logger();
print(identical(log1, log2)); // trueRückgabe verschiedener Subtypen:
class Shape {
factory Shape(String type) {
if (type == 'circle') return Circle();
if (type == 'square') return Square();
return Rectangle();
}
}
class Circle extends Shape { Circle() : super._(); }
class Square extends Shape { Square() : super._(); }
class Rectangle extends Shape { Rectangle() : super._(); }Factory-Konstruktoren sind nützlich, um die Instanzerstellung zu steuern, z. B. um gecachte Objekte zurückzugeben, Objekt-Pools zu implementieren oder basierend auf Eingabeparametern zu entscheiden, welcher Subtyp instanziiert werden soll.
Probier es selbst
import 'notification.dart';
void main() {
// TODO: Erstelle eine E-Mail-Benachrichtigung mit der Nachricht 'Welcome!'
// TODO: Erstelle eine SMS-Benachrichtigung mit der Nachricht 'Your code is 1234'
// TODO: Erstelle eine Push-Benachrichtigung mit der Nachricht 'New update available'
// TODO: Rufe send() für jede Benachrichtigung der Reihe nach auf
}
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 this-SchlüsselwortMethodenInstanzvariablenKonstruktor-GrundlagenWiederholung – Einfacher Taschenrechner4Null-Sicherheit
Einführung in Null-SicherheitNullable vs. Non-NullableDie ? und ! OperatorenLate-Schlüsselwort & Null-SicherheitNull-aware OperatorenNull-Sicherheit in KlassenZusammenfassung – Benutzerprofil-System7Abstrakte Klassen & Interfaces
Abstrakte KlassenAbstrakte MethodenInterfaces in DartImplizite InterfacesImplementieren vs. ErweiternMehrfache InterfacesRückblick – Shape Calculator10Collections & Generics
Überblick über List, Set und MapTypsichere CollectionsGenerische KlassenGenerische MethodenGenerische ConstraintsIterable & IteratorZusammenfassung – Generische Speicherung13Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums mit Methoden16Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen2Konstruktoren in Dart
Standard-KonstruktorBenannte KonstruktorenInitialisierungslistenKonstante KonstruktorenFactory-KonstruktorenWeiterleitende KonstruktorenZusammenfassung – Shape Builder5Kapselung
Öffentliche vs. private MemberDie _ Präfix-KonventionSichtbarkeit auf Library-EbeneGetter & Setter im DetailInformation HidingRückblick – Schülerdatensätze8Mixins
Einführung in MixinsMixins erstellenMehrere Mixins verwendenDas on-Schlüsselwort in MixinsMixin vs. VererbungMixin vs. InterfaceZusammenfassung - Tiersystem11Spezielle Methoden
toString() überschreibenhashCode & == überschreibenComparable-Interfacecall()-MethodenoSuchMethod überschreibenZusammenfassung – Eigene Collection14Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster3Klasseneigenschaften
Instanz- vs. statische MemberFinal & Const FelderLate-VariablenStatische Methoden & FelderGetter und SetterZusammenfassung – Bankkonto-Manager6Vererbung
Grundlagen der VererbungDas super-SchlüsselwortMethoden überschreibenDie @override-AnnotationDas final-Klassen-SchlüsselwortKonstruktoren & VererbungRückblick – Mitarbeiter-Hierarchie9Polymorphismus
Polymorphismus-GrundlagenPolymorphismus über InterfacesTypprüfung zur LaufzeitDie is & as OperatorenDas covariant SchlüsselwortZusammenfassung – Payment Processor