Singleton-Muster
Teil des Abschnitts Object Oriented Programming der Python-Journey von Coddy — Lektion 45 von 64.
Das Singleton-Muster stellt sicher, dass eine Klasse nur eine Instanz hat, und bietet einen globalen Zugriffspunkt darauf. Dies ist nützlich für Ressourcen wie Datenbankverbindungen oder Konfigurationseinstellungen.
Hier ist eine einfache Singleton-Implementierung:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instanceDie __new__-Methode steuert die Objekterzeugung. Sie prüft, ob bereits eine Instanz existiert, bevor sie eine neue erstellt.
Erstellen Sie zwei Instanzen der Singleton-Klasse:
singleton1 = Singleton()
singleton2 = Singleton()Prüfen Sie, ob beide Variablen auf dasselbe Objekt verweisen:
print(singleton1 is singleton2) # True
print(id(singleton1)) # Gleiche Speicheradresse
print(id(singleton2)) # Gleiche SpeicheradresseHier ist ein praxisorientierteres Beispiel mit einer Datenbankverbindung:
class DatabaseConnection:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.connection = "Connected to MySQL database"
print("Creating new database connection")
return cls._instance
def query(self, sql):
return f"Executing: {sql}"
# First access creates the connection
db1 = DatabaseConnection()
print(db1.connection)
# Second access reuses the same connection
db2 = DatabaseConnection()
print(db2.connection)
print(db1.query("SELECT * FROM users"))
print(db1 is db2)Erstellen Sie einen Konfigurationsmanager mit dem Singleton-Muster:
class Config:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.settings = {}
return cls._instance
def set_setting(self, key, value):
self.settings[key] = value
def get_setting(self, key):
return self.settings.get(key)
config1 = Config()
config1.set_setting("debug", True)
config2 = Config()
print(config2.get_setting("debug")) # True - dieselben EinstellungenAusgabe:
True
140234567890123
140234567890123
Creating new database connection
Connected to MySQL database
Connected to MySQL database
Executing: SELECT * FROM users
True
TrueKernpunkt: Das Singleton-Muster verwendet __new__, um die Objekterstellung zu steuern und sicherzustellen, dass nur eine Instanz existiert. Verwenden Sie es für Ressourcen, von denen es während der gesamten Anwendung nur eine Kopie geben sollte, wie Datenbankverbindungen, Logger oder Konfigurationsmanager. Denken Sie daran, dass alle Variablen, die auf ein Singleton zeigen, auf dasselbe Objekt im Speicher verweisen.
Aufgabe
EinfachIn dieser Challenge implementierst du das Singleton-Entwurfsmuster für eine Datenbankverbindungsklasse.
- Bearbeite
databaseconnection.py, um das Singleton-Muster gemäß den TODO-Kommentaren zu implementieren - Die Datei
driver.pyenthält umfangreiche Testszenarien und sollte nicht geändert werden
Spickzettel
Das Singleton-Muster stellt sicher, dass eine Klasse nur eine Instanz hat, und bietet einen globalen Zugriffspunkt darauf.
Grundlegende Singleton-Implementierung unter Verwendung von __new__:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instanceDie Methode __new__ steuert die Objekterzeugung, indem sie prüft, ob bereits eine Instanz existiert, bevor eine neue erstellt wird.
Testen von Singleton-Instanzen:
singleton1 = Singleton()
singleton2 = Singleton()
print(singleton1 is singleton2) # True - dasselbe ObjektPraktisches Beispiel mit einer Datenbankverbindung:
class DatabaseConnection:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.connection = "Connected to MySQL database"
return cls._instance
def query(self, sql):
return f"Executing: {sql}"Beispiel für einen Konfigurationsmanager:
class Config:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.settings = {}
return cls._instance
def set_setting(self, key, value):
self.settings[key] = value
def get_setting(self, key):
return self.settings.get(key)Verwenden Sie Singleton für Ressourcen, von denen es während der gesamten Anwendung nur eine Kopie geben sollte, wie Datenbankverbindungen, Logger oder Konfigurationsmanager.
Probier es selbst
from databaseconnection import DatabaseConnection
# Umfassender Testfall-Handler
test_case = input()
if test_case == "identity_check":
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2) # Sollte True ausgeben
elif test_case == "connect_state":
db = DatabaseConnection()
print(f"Initial connected state: {db.connected}") # Sollte False ausgeben
db.connect()
print(f"After connect: {db.connected}") # Sollte True ausgeben
elif test_case == "disconnect_state":
db = DatabaseConnection()
db.connect()
db.disconnect()
print(f"After disconnect: {db.connected}") # Sollte False ausgeben
elif test_case == "multiple_instances_same_state":
db1 = DatabaseConnection()
db1.connect()
db2 = DatabaseConnection()
print(f"db2 connected state: {db2.connected}") # Sollte True ausgeben
elif test_case == "host_value":
db = DatabaseConnection()
print(f"Default host: {db.host}") # Sollte "localhost" ausgeben
db.host = "new-server"
db2 = DatabaseConnection()
print(f"New instance host: {db2.host}") # Sollte "new-server" ausgeben
elif test_case == "init_once":
db1 = DatabaseConnection()
db1.host = "custom-host"
db2 = DatabaseConnection()
print(f"Both instances have same host: {db1.host == db2.host}") # Sollte True ausgeben
print(f"Host value: {db1.host}") # Sollte "custom-host" ausgeben
elif test_case == "connect_message":
db = DatabaseConnection()
db.connect() # Sollte "Connected to database at localhost" ausgeben
elif test_case == "disconnect_message":
db = DatabaseConnection()
db.connect()
db.disconnect() # Sollte "Disconnected from database" ausgeben
elif test_case == "attribute_modification":
db1 = DatabaseConnection()
db1.port = 3306
db2 = DatabaseConnection()
print(f"db2 has port attribute: {hasattr(db2, 'port')}") # Sollte True ausgeben
print(f"db2 port value: {db2.port}") # Sollte 3306 ausgeben
elif test_case == "reset_connection":
db1 = DatabaseConnection()
db1.connect()
print(f"Connected state: {db1.connected}") # Sollte True ausgeben
db2 = DatabaseConnection()
print(f"New instance connected state: {db2.connected}") # Sollte True ausgeben
db2.disconnect()
db3 = DatabaseConnection()
print(f"After disconnect, new instance state: {db3.connected}") # Sollte False ausgeben
elif test_case == "multiple_connects":
db = DatabaseConnection()
db.connect()
db.connect()
db.connect()
print(f"Connected state after multiple connects: {db.connected}") # Sollte True ausgeben
db.disconnect()
print(f"Connected state after disconnect: {db.connected}") # Sollte False ausgeben
elif test_case == "host_change_affects_message":
db = DatabaseConnection()
db.host = "custom-server"
db.connect() # Wird weiterhin "Connected to database at localhost" ausgeben
# Die connect-Methode hat eine fest codierte Nachricht, die das host-Attribut nicht verwendet
print("Message still shows localhost: True")Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Object Oriented Programming
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDer self-ParameterMethodenAttributeKonstruktor-Methode (__init__)Zusammenfassung – Einfacher Taschenrechner4Vererbung
Grundlagen der VererbungDie super()-FunktionMethoden überschreibenMehrfachvererbungMethod Resolution OrderZusammenfassung - Mitarbeiter-Hierarchie7Spezielle Methoden
Einführung in Magic MethodsOperator-ÜberladungMagic Methods für ContainerRückblick - Eigene Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster13Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung2Dekoratoren
Einführung in DekoratorenProperty-DekoratorStatischer Methoden-DekoratorKlassenmethoden-Dekorator5Polymorphismus
Methoden-Überschreiben vertieftDuck TypingAbstrakte Klassen und MethodenInterface-DesignZusammenfassung – Formen-Rechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungMixinsStatische und KlassenmethodenKlassendekoratorenContext Manager3Klasseneigenschaften
Instanz- vs. KlassenvariablenProperty-DekoratorenPrivate AttributeZusammenfassung – Bankkonto-Manager6Kapselung
Public, Protected, Private MemberZugriffsmodifikatorenInformation HidingProperty-Decorators für FortgeschritteneZusammenfassung - Studentenverwaltungssystem12Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen