Menu
Coddy logo textTech

Singleton-Muster

Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy — Lektion 90 von 110.

Das Singleton-Muster stellt sicher, dass eine Klasse während der gesamten Anwendung nur eine einzige Instanz hat, und bietet einen globalen Zugriffspunkt darauf. Dies ist nützlich, wenn genau ein Objekt benötigt wird, um Aktionen im gesamten System zu koordinieren – wie ein Konfigurationsmanager, eine Datenbankverbindung oder ein Protokollierungsdienst.

In Dart können Sie ein Singleton mithilfe eines Factory-Konstruktors in Kombination mit einer privaten statischen Instanz implementieren:

class AppConfig {
  static final AppConfig _instance = AppConfig._internal();
  
  String appName = 'MyApp';
  String version = '1.0.0';
  
  // Privater benannter Konstruktor
  AppConfig._internal();
  
  // Factory-Konstruktor gibt dieselbe Instanz zurück
  factory AppConfig() {
    return _instance;
  }
}

void main() {
  var config1 = AppConfig();
  var config2 = AppConfig();
  
  config1.appName = 'UpdatedApp';
  
  print(config2.appName);  // UpdatedApp
  print(identical(config1, config2));  // true
}

Der private Konstruktor _internal() verhindert die externe Instanziierung. Das statische Feld _instance hält die einzige Instanz, die einmalig beim Laden der Klasse erstellt wird. Jeder Aufruf von AppConfig() gibt dieselbe Instanz zurück, sodass Änderungen, die über eine Referenz vorgenommen werden, überall sichtbar sind.

Verwenden Sie Singletons sparsam – sie führen einen globalen Zustand ein, was das Testen erschweren kann. Sie eignen sich am besten für wirklich gemeinsam genutzte Ressourcen, die einen konsistenten Zustand über Ihre gesamte Anwendung hinweg erfordern.

challenge icon

Aufgabe

Einfach

Lass uns einen Manager für Spieleinstellungen mit dem Singleton-Muster erstellen! Du wirst ein System entwickeln, das sicherstellt, dass während der gesamten Anwendung nur eine Instanz der Spieleinstellungen existiert, sodass alle Teile deines Spiels dieselbe Konfiguration teilen.

Du wirst deinen Code in zwei Dateien organisieren:

  • game_settings.dart: Erstelle eine GameSettings-Klasse, die das Singleton-Muster implementiert. Dein Einstellungsmanager sollte Folgendes haben:
    • Eine private statische finale Instanz, die das einzige GameSettings-Objekt hält
    • Einen privaten benannten Konstruktor, um eine externe Instanziierung zu verhindern
    • Einen Factory-Konstruktor, der immer dieselbe Instanz zurückgibt
    • Drei Einstellungsfelder: difficulty (String, Standard: "Normal"), soundEnabled (bool, Standard: true) und playerName (String, Standard: "Player1")
    • Eine Methode displaySettings(), welche die aktuellen Einstellungen in diesem Format ausgibt: Settings: [playerName] | Difficulty: [difficulty] | Sound: [on/off] (gib "on" aus, wenn soundEnabled true ist, "off", wenn false)
  • main.dart: Importiere deine Spieleinstellungen und demonstriere, dass das Singleton korrekt funktioniert:
    • Hole die Einstellungsinstanz und nenne sie settings1
    • Rufe displaySettings() auf, um die Standardwerte anzuzeigen
    • Ändere die Einstellungen: Ändere playerName zu "Hero", difficulty zu "Hard" und soundEnabled zu false
    • Hole eine weitere Referenz auf die Einstellungen und nenne sie settings2
    • Rufe displaySettings() für settings2 auf, um zu beweisen, dass sie die über settings1 vorgenommenen Änderungen widerspiegelt
    • Gib aus, ob settings1 und settings2 identisch sind, unter Verwendung von: Same instance: [true/false]

Dies demonstriert den Hauptvorteil von Singletons – Änderungen, die irgendwo in deiner Anwendung vorgenommen werden, sind sofort überall sonst sichtbar, da es nur eine Instanz gibt!

Erwartete Ausgabe:

Settings: Player1 | Difficulty: Normal | Sound: on
Settings: Hero | Difficulty: Hard | Sound: off
Same instance: true

Spickzettel

Das Singleton-Muster stellt sicher, dass eine Klasse während der gesamten Anwendung nur eine einzige Instanz hat, und bietet einen globalen Zugriffspunkt darauf.

In Dart implementieren Sie ein Singleton mit einem Factory-Konstruktor in Kombination mit einer privaten statischen Instanz:

class AppConfig {
  static final AppConfig _instance = AppConfig._internal();
  
  String appName = 'MyApp';
  String version = '1.0.0';
  
  // Privater benannter Konstruktor
  AppConfig._internal();
  
  // Factory-Konstruktor gibt dieselbe Instanz zurück
  factory AppConfig() {
    return _instance;
  }
}

Schlüsselkomponenten:

  • static final _instance: Hält die einzelne Instanz, die einmal beim Laden der Klasse erstellt wird
  • _internal(): Privater Konstruktor verhindert externe Instanziierung
  • factory AppConfig(): Gibt jedes Mal dieselbe Instanz zurück

Anwendungsbeispiel:

var config1 = AppConfig();
var config2 = AppConfig();

config1.appName = 'UpdatedApp';

print(config2.appName);  // UpdatedApp
print(identical(config1, config2));  // true

Änderungen, die über eine Referenz vorgenommen werden, sind überall sichtbar, da alle Referenzen auf dieselbe Instanz zeigen.

Probier es selbst

import 'game_settings.dart';

void main() {
  // TODO: Hol dir die settings-Instanz und nenne sie settings1
  
  // TODO: Rufe displaySettings() auf, um die Standardwerte anzuzeigen
  
  // TODO: Ändere die Einstellungen:
  // - Ändere playerName in "Hero"
  // - Ändere difficulty in "Hard"
  // - Ändere soundEnabled in false
  
  // TODO: Hol dir eine weitere Referenz auf settings und nenne sie settings2
  
  // TODO: Rufe displaySettings() für settings2 auf, um zu beweisen, dass es die Änderungen widerspiegelt
  
  // TODO: Gib aus, ob settings1 und settings2 identisch sind
  // Format: Same instance: [true/false]
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung