In der Softwareentwicklung begegnen dir Muster wie Singleton und Factory immer wieder – auch in Dart. Beide Patterns bieten clevere Möglichkeiten, wie du Objekte effizient erstellst und verwaltest. Doch wann solltest du welches nutzen? Und wie unterscheiden sich die beiden eigentlich?
Was ist ein Singleton?
Die Grundidee hinter dem Singleton
Das Singleton-Pattern sorgt dafür, dass es von einer Klasse nur eine einzige Instanz gibt. Egal, wie oft du darauf zugreifst, es wird immer dieselbe Instanz zurückgegeben. Das ist praktisch für Zustandsverwaltung, Datenbanken oder Services, die sich zentral steuern lassen sollen.
Ein Beispiel wäre ein Service, der für die Datenbankkommunikation zuständig ist. Hier macht es Sinn, dass alle Teile deiner App dieselbe Instanz verwenden, um unnötige Duplikate zu vermeiden.
Wie du einen Singleton in Dart implementierst
Dart macht es dir leicht, ein Singleton zu bauen. Der Schlüssel liegt in einem privaten Konstruktor und einer statischen Instanz.
class SingletonExample {
SingletonExample._privateConstructor(); // Privater Konstruktor
static final SingletonExample _instance = SingletonExample._privateConstructor();
static SingletonExample get instance => _instance;
void doSomething() {
print("Ich bin ein Singleton!");
}
}
void main() {
final obj1 = SingletonExample.instance;
final obj2 = SingletonExample.instance;
print(obj1 == obj2); // true, beide sind dieselbe Instanz
}
Wann solltest du Singleton verwenden?
- Globale Zustände: Wenn du Daten oder Dienste über mehrere Teile der App hinweg teilen musst (z. B. ein Logging-Service).
- Zentrale Kontrolle: Für Instanzen, die ressourcenintensiv sind und nicht mehrfach erstellt werden sollen, wie eine Datenbankverbindung.
- Speicheroptimierung: Reduziert unnötige Duplikate von Objekten.
Was ist eine Factory?
Die Grundidee hinter der Factory
Das Factory-Pattern geht einen Schritt weiter: Es gibt dir die Kontrolle darüber, wie und wann Objekte erstellt werden. Anstatt immer eine neue Instanz zu erstellen, kannst du entscheiden, ob du z. B. ein bereits bestehendes Objekt zurückgibst oder basierend auf Eingaben eine spezielle Unterklasse erzeugst.
Das Factory-Pattern ist flexibler als ein Singleton, da es nicht darauf beschränkt ist, immer dieselbe Instanz zurückzugeben. Stattdessen kapselst du die gesamte Logik der Objekterstellung in einer einzigen Stelle.
Wie du eine Factory in Dart implementierst
In Dart kannst du mit dem factory-Keyword einen Factory-Konstruktor erstellen. Hier ein Beispiel:
class Shape {
factory Shape(String type) {
if (type == 'circle') {
return Circle();
} else if (type == 'square') {
return Square();
} else {
throw ArgumentError('Unbekannter Typ: $type');
}
}
}
class Circle extends Shape {}
class Square extends Shape {}
void main() {
final shape1 = Shape('circle');
final shape2 = Shape('square');
print(shape1.runtimeType); // Circle
print(shape2.runtimeType); // Square
}
Wann solltest du Factory verwenden?
- Dynamische Objekterstellung: Wenn die Instanzierung von bestimmten Bedingungen abhängt (z. B. welcher Typ von
Shapebenötigt wird). - Abstraktion: Wenn du die eigentliche Instanzierung hinter einer klaren Schnittstelle verstecken möchtest.
- Wiederverwendbarkeit: Wenn du komplexe Logik für die Erstellung von Objekten zentralisieren möchtest.
Singleton vs. Factory: Der Vergleich
| Feature | Singleton | Factory |
|---|---|---|
| Rückgabewert | Immer dieselbe Instanz | Kann neue oder vorhandene Instanzen zurückgeben |
| Zweck | Globale Instanzverwaltung | Flexible Objekterstellung |
| Flexibilität | Beschränkt auf eine einzige Instanz | Kann unterschiedliche Objekte erstellen |
| Komplexität | Einfach | Etwas komplexer |
| Typisches Szenario | Datenbankverbindung, Logging | Dynamische Typenwahl, polymorphe Objekte |
Was, wenn du beides kombinierst?
Manchmal möchtest du die Vorteile von Singleton und Factory zusammen nutzen. Zum Beispiel könntest du eine Factory verwenden, um sicherzustellen, dass eine bestimmte Klasse als Singleton zurückgegeben wird, während andere Klassen dynamisch erstellt werden.
class ServiceFactory {
static final _singletonService = SingletonExample._privateConstructor();
factory ServiceFactory(String type) {
if (type == 'singleton') {
return _singletonService;
} else if (type == 'newService') {
return NewService();
} else {
throw ArgumentError('Unbekannter Typ: $type');
}
}
}
class SingletonExample {
SingletonExample._privateConstructor();
}
class NewService {}
void main() {
final singleton = ServiceFactory('singleton');
final newService = ServiceFactory('newService');
print(singleton.runtimeType); // SingletonExample
print(newService.runtimeType); // NewService
}
Wann solltest du welches Pattern wählen?
- Wähle Singleton, wenn:
- Du garantieren musst, dass es nur eine Instanz gibt.
- Es sich um zentrale, globale Dienste handelt.
- Wähle Factory, wenn:
- Die Logik der Objekterstellung dynamisch ist.
- Du Objekte basierend auf Bedingungen oder Typen erzeugen möchtest.
Fazit
Singleton und Factory sind keine Konkurrenz, sondern ergänzende Werkzeuge. Der Singleton sorgt für eine konsistente Instanz, während die Factory dir Flexibilität bei der Objekterstellung gibt. Beide haben ihre Stärken, und wenn du sie geschickt einsetzt, kannst du deine Dart-Anwendungen noch robuster und effizienter gestalten.

Schreiben Sie einen Kommentar