Singleton-Muster
Teil des Abschnitts Object Oriented Programming der Python-Journey von Coddy — Lektion 45 von 64.
Das Singleton-Muster stellt sicher, dass eine class has only one instance und einen globalen access-Punkt darauf bereitstellt. Dies ist nützlich für Ressourcen wie database-Verbindungen oder Konfigurations-settings.
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 Objekterstellung. Sie prüft, ob bereits eine Instanz existiert, bevor eine neue erstellt wird.
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 praktischeres Beispiel mit einer Datenbankverbindung (DatabaseConnection):
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}"
# Erster Zugriff erstellt die Verbindung
db1 = DatabaseConnection()
print(db1.connection)
# Zweiter Zugriff verwendet dieselbe Verbindung erneut
db2 = DatabaseConnection()
print(db2.connection)
print(db1.query("SELECT * FROM users"))
print(db1 is db2)Erstelle einen Konfigurationsmanager unter Verwendung des Singleton-Musters:
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 - gleiche EinstellungenAusgabe:
True
140234567890123
140234567890123
Creating new database connection
Connected to MySQL database
Connected to MySQL database
Executing: SELECT * FROM users
True
TrueWichtiger Punkt: Das Singleton-Muster verwendet __new__, um die Objekterstellung zu steuern und sicherzustellen, dass nur eine einzige Instanz existiert. Verwenden Sie es für Ressourcen, von denen es in Ihrer gesamten Anwendung nur eine einzige Kopie geben sollte, wie z. B. Datenbankverbindungen, Logger oder Konfigurations-Manager. Denken Sie daran, dass alle Variablen, die auf ein Singleton zeigen, auf dasselbe Objekt im Speicher verweisen.
Aufgabe
EinfachIn dieser Herausforderung wirst du das Singleton-Entwurfsmuster für eine Datenbankverbindungsklasse implementieren.
- 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
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() # Should print "Connected to database at localhost"
elif test_case == "disconnect_message":
db = DatabaseConnection()
db.connect()
db.disconnect() # Should print "Disconnected from database"
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() # Will still print "Connected to database at localhost"
# Die connect-Methode hat eine hardcodierte 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 BenutzerklassenAusleihsystemSuchfunktionalitätAdmin-InterfaceTesten und Integration