Singleton-Muster
Teil des Abschnitts Objektorientierte Programmierung der GDScript-Journey von Coddy. Lektion 46 von 65.
Das Singleton-Muster stellt sicher, dass eine Klasse genau ein Objekt hat, und bietet jedem Skript eine Möglichkeit, darauf zuzugreifen. Verwende es für Dinge, von denen es in einem Spiel nur eines gibt: die Einstellungen, das Speichersystem, die Punkteverwaltung.
In GDScript enthält eine static var das einzelne Objekt, und eine static func erstellt es, wenn zum ersten Mal danach gefragt wird:
# game_settings.gd
class_name GameSettings
extends RefCounted
static var _instance: GameSettings = null
var volume := 50
static func get_instance() -> GameSettings:
if _instance == null:
_instance = GameSettings.new()
print("Creating settings")
return _instance_instance gehört zur Klasse, nicht zu einem Objekt, daher sieht jedes Skript dieselbe Variable. Beim ersten Aufruf ist sie leer und das Objekt wird erstellt; jeder spätere Aufruf gibt dasselbe Objekt zurück.
# main.gd
var a := GameSettings.get_instance()
var b := GameSettings.get_instance()
a.volume = 80
print(b.volume)
print(a == b)Creating settings
80
truea und b sind zwei Variablen, die dasselbe Objekt enthalten, daher ist die über a vorgenommene Änderung auch über b sichtbar. Bei Objekten ist == nur dann true, wenn beide Seiten dasselbe Objekt sind.
GDScript kann _init() nicht privat machen, daher hindert nichts ein Skript daran, GameSettings.new() aufzurufen und ein zweites Objekt zu erhalten. Der Unterstrich in _instance und die Methode get_instance() bilden die Vereinbarung: Skripte fragen nach dem Objekt, sie erstellen es niemals selbst.
In einem Godot-Projekt erhält man ein gemeinsam genutztes Objekt üblicherweise über einen Autoload: ein Skript, das du in den Projekteinstellungen registrierst und das Godot beim Start des Spiels einmal erstellt und in jedem Skript unter seinem Namen verfügbar macht. Es ist ein Singleton, das Godot für dich verwaltet. Autoloads werden im Editor eingerichtet, daher bauen die Herausforderungen hier das Muster mit static var im Code nach.
Aufgabe
EinfachJede Münze in einem Spiel erhöht einen gemeinsamen Punktestand. Mache ScoreManager zu einem Singleton:
- Ein
static varenthält das einzelne Objekt. static func get_instance()gibt es zurück und erstellt es beim ersten Aufruf. Direkt nach der Erstellung gibt esScore manager createdaus.add_points(points)addiert Punkte zuscore.
In coin.gd addiert collect() den value der Münze über ScoreManager.get_instance() zum Punktestand.
Der bereitgestellte Code liest ein, wie viele Ereignisse folgen, und danach ein Ereignis pro Zeile: coin VALUE sammelt eine neue Münze ein, bonus POINTS addiert direkt Punkte. Nach jedem Ereignis gibt er den Punktestand aus und am Ende, ob zwei Aufrufe von get_instance() dasselbe Objekt zurückgeben. Für coin 5 und bonus 20 lautet die Ausgabe:
Score manager created
Score: 5
Score: 25
Same object: trueDein Code gehört in score_manager.gd und coin.gd. main.gd enthält den bereitgestellten Eingabe-/Ausgabecode und kann nicht bearbeitet werden.
Probier es selbst
extends Node
func _ready():
# Vorgegebener Ein-/Ausgabecode: unverändert lassen
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ")
if parts[0] == "coin":
Coin.new(int(parts[1])).collect()
elif parts[0] == "bonus":
ScoreManager.get_instance().add_points(int(parts[1]))
print("Score: %d" % ScoreManager.get_instance().score)
print("Same object: %s" % (ScoreManager.get_instance() == ScoreManager.get_instance()))
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 DateienEinführung in die OOPKlassen vs. ObjekteDas Schlüsselwort selfMethodenEigenschaftenKonstruktor (_init)Wiederholung – Einfacher Taschenrechner4Polymorphie
Methodenüberschreibung erneut betrachtetDuck-TypisierungAbstrakte Klassen und MethodenSchnittstellendesignRückblick – Formrechner2Klassenattribute
Instanz- vs. statische VariablenStatische FunktionenProperty-SetterProperty-GetterPrivat nach KonventionWiederholung – Bankkontenverwaltung5Kapselung
Öffentliche und private MemberValidierung mit SetternInformationsverbergenSchreibgeschützte EigenschaftenRückblick – System zur Schülerverwaltung8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungInnere KlassenNodes als KomponentenRefCounted vs. NodeEnums in Klassen11Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Vererbung
Grundlegende VererbungDas Schlüsselwort superMethodenüberschreibungVererbungskettenTypprüfungen mit isWiederholung – Mitarbeiterhierarchie6Spezielle Methoden
Einführung in virtuelle MethodenDie _to_string-MethodeBenutzerdefinierte IteratorenRückblick – Benutzerdefinierte Liste9Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterBeobachter-MusterStrategie-Muster12Abschließende Herausforderungen
E-Learning-PlattformBankensystemEntwicklung von SpielfigurenFahrzeugvermietungÜbe selbstständig: Online-GDScript-Compiler